首页 > 代码库 > POJ 3728 离线 LCA

POJ 3728 离线 LCA

题意很简单

给一个树(n < 5w) 每个点有个权值,代表商品价格

若干个询问(5w)


对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品,   最大可能是多少

注意一条路径上只能买卖一次,先买才能卖


用的方法是离线LCA,在上面加了一些东西

对于一个询问, 假设u,v的LCA是f

那么有三种可能, 一个是从u到f 买卖了。 一个是从f到v买卖了,  一个是从u到f之间买了,从v到f卖了

从u到f 我们称为up,  从f到v我们称为down,而从u到f买然后在f到v卖就是求u到f的最小值和f到v的最大值。


我们要分别求这三个值

实际上就是在离线tarjan求LCA的过程中求出的

对于每个点, 我们进行dfs的时候,查看于其相关的询问,

假设当前点是u, 询问的点是v, u和v的LCA是f,如果v已经dfs过了,说明v在并查集中的祖先就是u,v的LCA  f点, 

将该询问加入到f的相关集合中,等f所有的子节点都处理过后再去处理f, 就可以发现,一切都是顺其自然了

在这些处理过程中,up和down以及u,v到f的最大值最小值  都可以在并查集求压缩路径的过程中更新。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <ctime>
#define MAXN 52222
#define MAXM 222222
#define INF 1000000001
using namespace std;
vector<int>g[MAXN], st[MAXN], ed[MAXN], id[MAXN], ask[MAXN], pos[MAXN];
int mx[MAXN], mi[MAXN], up[MAXN], down[MAXN], vis[MAXN], fa[MAXN], ans[MAXN];
int n, Q;
int find(int x) {
    if(x == fa[x]) return x;
    int y = fa[x];
    fa[x] = find(y);
    up[x] = max(up[x], max(mx[y] - mi[x], up[y]));
    down[x] = max(down[x], max(mx[x] - mi[y], down[y]));
    mx[x] = max(mx[x], mx[y]);
    mi[x] = min(mi[x], mi[y]);
    return fa[x];
}
void tarjan(int u) {
    vis[u] = 1;
    for(int i = 0; i < ask[u].size(); i++) {
        int v = ask[u][i];
        if(vis[v]) {
            int t = find(v);
            int z = pos[u][i];
            if(z > 0) {
                st[t].push_back(u);
                ed[t].push_back(v);
                id[t].push_back(z);
            } else {
                st[t].push_back(v);
                ed[t].push_back(u);
                id[t].push_back(-z);
            }
        }
    }
    for(int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if(!vis[v]) {
            tarjan(v);
            fa[v] = u;
        }
    }
    for(int i = 0; i < st[u].size(); i++) {
        int a = st[u][i];
        int b = ed[u][i];
        int t = id[u][i];
        find(a);
        find(b);
        ans[t] = max(up[a], max(down[b], mx[b] - mi[a]));
    }
}

int main() {
        scanf("%d", &n);
        int u, v, w;

        for(int i = 1; i <= n; i++) {
            scanf("%d", &w);
            mx[i] = mi[i] = w; fa[i] = i;
        }
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);

        }
        scanf("%d", &Q);
        for(int i = 1; i <= Q; i++) {
            scanf("%d%d", &u, &v);
            ask[u].push_back(v);
            pos[u].push_back(i);
            ask[v].push_back(u);
            pos[v].push_back(-i);
        }
        tarjan(1);
        for(int i = 1; i <= Q; i++) printf("%d\n", ans[i]);

    return 0;
}



POJ 3728 离线 LCA