水果姐第二天心情也很不错,又来逛水果街。
突然,cgh又出现了。cgh施展了魔法,水果街变成了树结构(店与店之间只有一条唯一的路径)。
同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
cgh给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去。求最多可以赚多少钱。
水果姐向学过oi的你求助。
第一行n,表示有n家店
下来n个正整数,表示每家店一个苹果的价格。
下来n-1行,每行两个整数x,y,表示第x家店和第y家店有一条边。
下来一个整数m,表示下来有m个询问。
下来有m行,每行两个整数x和y,表示从第x家店出发到第y家店。
输出描述 Output Description
有m行。
每行对应一个询问,一个整数,表示面对cgh的每次询问,水果姐最多可以赚到多少钱。
10
16 5 1 15 15 1 8 9 9 15
1 2
1 3
2 4
2 5
2 6
6 7
4 8
1 9
1 10
6
9 1
5 1
1 7
3 3
1 1
3 6
7
11
7
0
0
15
0<=苹果的价格<=10^8
0 < n<=200000
0 < m<=10000
不得不说这个lca真的好恶心!!
记录不知道多少个值:
anc[x][i]:x往上(1<<i)的祖先。
maxn[x][i]:x到anc[x][i]的最大值。
minn[x][i]:x到anc[x][i]的最小值。
ans1[x][i]:从anc[x][i]走到x的答案。
ans2[x][i]:从x走到anc[x][i]的答案。
假设路线是x->y,并x在lca左边,y在lca右边。
这样,答案只会在:
lca左边
lca右边
lca右边的最大值-lca左边的最小值
对于左边,要时刻用未来的最大值-历史的最小值更新答案。
对于右边,要时刻用历史的最大值-当前的最小值更新答案。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int size=400010;
const int INF=233333333;
int head[size],nxt[size],to[size],tot=0;
int num[size];
int maxn[size][30],minn[size][30],anc[size][30],ans1[size][30],ans2[size][30];
//ans1:从上到下 ans2:从下到上
int deep[size];
void build(int f,int t)
{
to[++tot]=t;
nxt[tot]=head[f];
head[f]=tot;
}
void dfs(int u,int fa)
{
if(deep[u]) return ;
deep[u]=deep[fa]+1;
minn[u][0]=min(num[u],num[fa]);
maxn[u][0]=max(num[u],num[fa]);
ans1[u][0]=max(0,num[u]-num[fa]);
ans2[u][0]=max(0,num[fa]-num[u]);
anc[u][0]=fa;
for(int i=1;anc[u][i-1];i++)
{
anc[u][i]=anc[anc[u][i-1]][i-1];
maxn[u][i]=max(maxn[u][i-1],maxn[anc[u][i-1]][i-1]);
minn[u][i]=min(minn[u][i-1],minn[anc[u][i-1]][i-1]);
ans1[u][i]=max( max(ans1[u][i-1],ans1[anc[u][i-1]][i-1]) , maxn[u][i-1]-minn[anc[u][i-1]][i-1] );
ans2[u][i]=max( max(ans2[u][i-1],ans2[anc[u][i-1]][i-1]) , maxn[anc[u][i-1]][i-1]-minn[u][i-1] );
}
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
dfs(v,u);
}
}
int asklca(int x,int y)
{
int ans=0;
if(deep[x]<deep[y]) swap(x,y);
if(deep[x]>deep[y])
{
int dd=deep[x]-deep[y];
for(int i=24;i>=0;i--)
{
if(dd&(1<<i))
{
x=anc[x][i];
}
}
}
if(x!=y)
{
for(int i=24;i>=0;i--)
{
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
}
}
if(x==y) return x;
else return anc[x][0];
}
int ask(int x,int y)
{
int lca=asklca(x,y);
int maxx=-INF,minnn=INF,ans=0;
int dd1=deep[x]-deep[lca];
if(dd1>0)
{
for(int i=24;i>=0;i--)
{
if(dd1&(1<<i))
{
ans=max(ans, max(ans2[x][i],maxn[x][i]-minnn) );
minnn=min(minn[x][i],minnn);
x=anc[x][i];
}
}
}
int dd2=deep[y]-deep[lca];
if(dd2>0)
{
for(int i=24;i>=0;i--)
{
if(dd2&(1<<i))
{
ans=max(ans, max(ans1[y][i],maxx-minn[y][i]) );
maxx=max(maxn[y][i],maxx);
y=anc[y][i];
}
}
}
return max(ans,maxx-minnn);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
for(int i=1;i<=n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
build(a,b); build(b,a);
}
dfs(1,0);
int q;
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",ask(x,y));
}
return 0;
}