【刷题笔记】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;
}
posted @ 2025-05-13 14:39  GuoSN0410  阅读(12)  评论(0)    收藏  举报