POJ 3728 The merchant(在线倍增LCA,维护树上最大,最小,两点差值最大。)

Description 
n个城市构成一棵树,每个城市都有一种商品有一个固定的价格,一个商人要从一个城市到另一个城市,他会在路途中选取一个城市购买这种商品然后在之后的某个城市卖掉以赚取差价,问最大差价 
Input 
第一行一整数n表示城市个数,之后n个整数val[i]表示第i个城市该种商品的价格,之后n-1行每行两个整数u和v表示u城市和v城市有路径,然后输入一整数q表示查询数,每次查询输入两个整数u和v表示商人从u到v路途中可以赚取的最大差价(1<=n,val[i],q<=50000) 
Output 
对于每组查询输出一个答案 
Sample Input 





1 3 
3 2 
3 4 

1 2 
1 3 
1 4 
2 3 
2 1 
2 4 
3 1 
3 2 
3 4 
Sample Output 








思路:

我们求的是一个城市到另外一个城市, 在之前买一个商品,在之后卖出,求最大。

卖一定在买之前。

所以我们在线倍增维护几个值,

Max[i][j]  i 到i 的 2 的 j 次方 之间的最大值,

Min[i][j]   最小值,

Up[i][j]  从 i 到 i 的j 次方父亲之间差值最大,

Down[i][j]  从i 的j 次方,到 i 之间的差值最大。

所以我们最后找到两个城市的最近公共祖先,然后我们在求最后的答案,

无非是, Up[x][k]   Down[y][k]  , x 到 k 的最小值 与 y 到 k 的最大值 两者之间差值。

x 是起点城市,y 是终点城市, k 是公共祖先。

接下来就是维护了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define rep(i,a,b)  for (int i = a; i < b; i++)
#define per(i,a,b)  for (int i = a; i > b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 1e5+10;
vector<int>g[N];
int f[N][20],Max[N][20],Min[N][20],Up[N][20],Down[N][20];
int dep[N],a[N],n;
void dfs(int u, int fa){
	for (int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if (v == fa) continue;
		f[v][0] = u;
		dep[v] = dep[u] + 1;
		Max[v][0] = max(a[v],a[u]);
		Min[v][0] = min(a[v],a[u]);
		Up[v][0] = max(0,a[u] - a[v]);
		Down[v][0] = max(0,a[v] - a[u]);
		dfs(v,u);
	}
	return;
}


void init(){
	mem(f,-1);
	dep[1] = 1;
	dfs(1,0);
	for (int j = 1; j < 20; j++)
		for (int i = 1; i <= n; i++)
			if (~f[i][j-1]){
				int a,b,k = f[i][j-1];
				f[i][j] = f[k][j-1];
				Max[i][j] = max(Max[i][j-1],Max[k][j-1]);
				Min[i][j] = min(Min[i][j-1],Min[k][j-1]);
				a = max(0,Max[k][j-1] - Min[i][j-1]);
				b = max(Up[i][j-1],Up[k][j-1]);
				Up[i][j] = max(a,b);
				a = max(0,Max[i][j-1]-Min[k][j-1]);
				b = max(Down[i][j-1],Down[k][j-1]);
				Down[i][j] = max(a,b);
			}
	return;
}
int lca(int x, int y){
	if (dep[x] < dep[y]) swap(x,y);
	per(i,19,-1)
	if (dep[f[x][i]] >= dep[y]) x = f[x][i];
	if (x == y) return x;
	per(i,19,-1)
	if (f[x][i] != f[y][i]){
		x = f[x][i];
		y = f[y][i];
	}
	return f[x][0];
}
int Query_up(int x, int deep, int &min_val){
	int ans = 0;
	per(i,19,-1)
	if (deep & (1 << i)){
		ans = max(ans,Up[x][i]);
		ans = max(ans,Max[x][i] - min_val);
		min_val = min(min_val,Min[x][i]);
		x = f[x][i];
	}
	return ans;
}
int Query_down(int x, int deep, int &max_val){
	int ans = 0;
	per(i,19,-1)
	if (deep & (1 << i)){
		ans = max(ans,Down[x][i]);
		ans = max(ans,max_val-Min[x][i]);
		max_val = max(max_val,Max[x][i]);
		x = f[x][i];
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	rep(i,1,n+1)
	scanf("%d",&a[i]);
	rep(i,0,n+1)
	g[i].clear();
	rep(i,1,n){
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	init(); int m;
	scanf("%d",&m);
	while(m--){
		int x,y,z;
		scanf("%d%d",&x,&y);
		z = lca(x,y);
		int max_val = 0, min_val = INF,a,b;
		a = Query_up(x,dep[x] - dep[z],min_val);
		b = Query_down(y,dep[y] - dep[z],max_val);
		z = max(max(0,max_val - min_val),max(a,b));
		printf("%d\n",z);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/81563967