题意很简单
给一个树(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; }
时间: 2024-10-10 10:37:43