(赛前练手#5)POJ3728 The merchant(倍增)

版权声明:转载请声明出处,谢谢支持 https://blog.csdn.net/Dreamstar_DS/article/details/83246130

要是求路径MAX、MIN可能大家直接树剖了…
但是本题要求的是一条单向路径,且要先买后卖
于是我们要想方设法优化暴力模拟沿路径走的这一过程
于是各位想到了(倍增!)
我们设
maxx[i][j] 为从i向上走(1 << j)步所经过的最大点权
minn[i][j]为从i向上走(1 << j)步所经过的最小点权
up[i][j] 为从i向上走(1 << j)步的最大答案
minn[i][j]为向下走(1 << j)步到i的最大答案
(刚刚已经阐述了,up[i][j]和minn[i][j]可能不同)
AC Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define rg register
#define il inline
#define ll long long
#define maxn 100005
using namespace std;
il int read(){rg int x = 0 , w = 1;rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') w = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}return x * w;}
int f[maxn][21] , up[maxn][21] , down[maxn][21] , maxx[maxn][21] , minn[maxn][21];
int dep[maxn] , p[maxn];
struct edge{
	int to , next;	
}e[maxn << 2];
int head[maxn] , cnt;
void add(int u , int v){
	e[++cnt].to = v;
	e[cnt].next = head[u];
	head[u] = cnt;
}
void dfs(int u , int fa){
	dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	maxx[u][0] = max(p[u] , p[fa]);
	minn[u][0] = min(p[u] , p[fa]);
	up[u][0] = p[fa] - p[u];
	down[u][0] = p[u] - p[fa];
	for (rg int i = 1 ; i <= 17 ; ++i)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for (rg int i = 1 ; i <= 17 ; ++i){
		maxx[u][i] = max(maxx[u][i - 1] , maxx[f[u][i - 1]][i - 1]);
		minn[u][i] = min(minn[u][i - 1] , minn[f[u][i - 1]][i - 1]);
		up[u][i] = max(max(up[u][i - 1] , up[f[u][i - 1]][i - 1]) , maxx[f[u][i - 1]][i - 1] - minn[u][i - 1]);
		down[u][i] = max(max(down[u][i - 1] , down[f[u][i - 1]][i - 1]) , maxx[u][i - 1] - minn[f[u][i - 1]][i - 1]);
	}
	for (rg int i = head[u] ; i ; i = e[i].next){
		rg int to = e[i].to;
		if (to != fa)
			dfs(to , u);	
	}
}
int lca(int a , int b){
	if (dep[a] > dep[b]) a ^= b , b ^= a , a ^= b;
	for (rg int i = 17 ; i >= 0 ; --i)
		if (dep[b] - dep[a] >= (1 << i))
			b = f[b][i];
	if (a == b) return a;
	for (rg int i = 17 ; i >= 0 ; --i)
		if (f[a][i] != f[b][i])
			a = f[a][i] , b = f[b][i];
	return f[a][0];
}
int query1(int a , int lca0 , int &minl){
	rg int ans = -1;
	minl = 9999999;
	for (rg int i = 17 ; i >= 0 ; --i)
		if (dep[a] - dep[lca0] >= (1 << i)){
			ans = max(ans , max(up[a][i] , maxx[a][i] - minl));
			minl = min(minl , minn[a][i]);
			a = f[a][i];
		}
	return ans;
}
int query2(int b , int lca0 , int &maxl){
	rg int ans = -1;
	maxl = -1;
	for (rg int i = 17 ; i >= 0 ; --i)
		if (dep[b] - dep[lca0] >= (1 << i)){
			ans = max(ans , max(down[b][i] , maxl - minn[b][i]));
			maxl = max(maxl , maxx[b][i]);
			b = f[b][i];
		}
	return ans;
}
int main(){
	rg int n = read() , u , v , w;
	for (rg int i = 1 ; i <= n ; ++i)
		p[i] = read();
	dep[1] = 1;
	for (rg int i = 1 ; i < n ; ++i){
		rg int u = read() , v = read();
		add(u , v);add(v , u);
	}
	dfs(1 , 0);
	rg int q = read() , maxl , minl , ans;
	for (rg int i = 1 ; i <= q ; ++i){
		u = read() , v = read();
		ans = -1;
		rg int lcaa = lca(u , v);
		rg int x1 = query1(u , lcaa , minl) , x2 = query2(v , lcaa , maxl);
		printf("%d\n" , max(max(max(x1 , x2) , maxl - minl) , 0));
	}
	return 0;	
}

猜你喜欢

转载自blog.csdn.net/Dreamstar_DS/article/details/83246130