【刷题笔记】The merchant
思路
对于 \(u, v\) 路径上的最大利润有三种情况:
- \(u->lca(u,v)\) 上买卖;
- \(lca(u,v)->v\) 上买卖;
- 跨过 \(lca(u,v)\) 进行买卖;
我们可以用树上倍增进行维护。设 up 数组维护第一种买卖,down 数组维护第二种买卖,maxx 维护路径最大值,minn 维护最小值。
在维护倍增数组时,也有三种情况:\(i-1\) 号祖先下面,\(i-1\) 号祖先上面,跨过 \(i-1\) 号祖先;
f[u][i] = f[f[u][i - 1]][i - 1];
up[u][i] = max(up[u][i - 1], max(up[f[u][i - 1]][i - 1], Max[f[u][i - 1]][i - 1] - Min[u][i - 1]));
down[u][i] = max(down[u][i - 1], max(down[f[u][i - 1]][i - 1], Max[u][i - 1] - Min[f[u][i - 1]][i - 1]));
Max[u][i] = max(Max[u][i - 1], Max[f[u][i - 1]][i - 1]);
Min[u][i] = min(Min[u][i - 1], Min[f[u][i - 1]][i - 1]);
再向上跳跃时,也同样有三种情况:已经跳到的点下面,已经跳到的点继续向上跳,跨过当前所在点。
int ans = 0, minn = INF, maxx = 0;
for(int i = 0; i <= 20; i++){
if(len1 & 1){
ans = max(ans, max(up[x][i], Max[x][i] - minn));
minn = min(minn, Min[x][i]);
x = f[x][i];
}
len1 >>= 1;
}
for(int i = 0; i <= 20; i++){
if(len2 & 1){
ans = max(ans, max(down[y][i], maxx - Min[y][i]));
maxx = max(maxx, Max[y][i]);
y = f[y][i];
}
len2 >>= 1;
}
code
#include<cstdio>
#include<iostream>
#define INF 2147483647
#define N 100010
#define M 40
using namespace std;
struct edge{
int to, next;
}e[N << 2];
int n, head[N], cnt = 0, w[N], q;
int dep[N];
int up[N][M], down[N][M], f[N][M], Max[N][M], Min[N][M];
void add(int x, int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
void dfs(int u, int fa){
dep[u] = dep[fa] + 1;
f[u][0] = fa, up[u][0] = max(w[fa] - w[u], 0), down[u][0] = max(w[u] - w[fa], 0);
Max[u][0] = max(w[u], w[fa]), Min[u][0] = min(w[u], w[fa]);
for(int i = 1; (1 << i) <= dep[u]; i++){
f[u][i] = f[f[u][i - 1]][i - 1];
up[u][i] = max(up[u][i - 1], max(up[f[u][i - 1]][i - 1], Max[f[u][i - 1]][i - 1] - Min[u][i - 1]));
down[u][i] = max(down[u][i - 1], max(down[f[u][i - 1]][i - 1], Max[u][i - 1] - Min[f[u][i - 1]][i - 1]));
Max[u][i] = max(Max[u][i - 1], Max[f[u][i - 1]][i - 1]);
Min[u][i] = min(Min[u][i - 1], Min[f[u][i - 1]][i - 1]);
}
for(int i = head[u]; i; i = e[i].next){
int v = e[i].to;
if(v == fa) continue;
dfs(v, u);
}
}
int Lca(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
int len = dep[x] - dep[y];
for(int i = 0; i <= 20; i++){
if(len & 1) x = f[x][i];
len >>= 1;
}
if(x == y) return x;
for(int i = 20; i >= 0; i--){
if(f[x][i] != f[y][i]){
x = f[x][i], y = f[y][i];
}
}
return f[x][0];
}
int ask(int x, int y, int lca){
int len1 = dep[x] - dep[lca];
int len2 = dep[y] - dep[lca];
int ans = 0, minn = INF, maxx = 0;
for(int i = 0; i <= 20; i++){
if(len1 & 1){
ans = max(ans, max(up[x][i], Max[x][i] - minn));
minn = min(minn, Min[x][i]);
x = f[x][i];
}
len1 >>= 1;
}
for(int i = 0; i <= 20; i++){
if(len2 & 1){
ans = max(ans, max(down[y][i], maxx - Min[y][i]));
maxx = max(maxx, Max[y][i]);
y = f[y][i];
}
len2 >>= 1;
}
return max(ans, maxx - minn);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> w[i];
int x, y;
for(int i = 1; i < n; i++){
cin >> x >> y;
add(x, y), add(y, x);
}
dfs(1, 0);
cin >> q;
while(q--){
cin >> x >> y;
int lca = Lca(x, y);
cout << ask(x, y, lca) << endl;
}
return 0;
}

浙公网安备 33010602011771号