这个题算是LCA的一个高级应用吧。
其实就是在维护u,v到其最近公共祖先的几个数据(将u,v分成两段,一个从u到LCA(u,v),一个从LCA(u,v)到v,分别维护即可)
#include<cstdio>
#include<string.h>
#include<math.h>
#define con 50100
using namespace std;
int head1[con],head2[con],head3[con],p,n,num[con],mi[con],mx[con],up[con],down[con],vis[con],f[50100],ans[con];
struct Edge{
int f;
int to;
int d;
int next;
}edge[con*4];
int max(int a,int b){
return a>b?a:b;
}
int min(int a,int b){
return a>b?b:a;
}
int find(int u){ //这里用递归与分治更新数据
if(f[u]==u)return u;
int tem=f[u];
f[u]=find(f[u]);
up[u]=max(max(up[u],up[tem]),mx[tem]-mi[u]);
down[u]=max(max(down[u],down[tem]),mx[u]-mi[tem]);
mx[u]=max(mx[u],mx[tem]);
mi[u]=min(mi[u],mi[tem]);
return f[u];
}
void tarjan(int u){
int i,j;
f[u]=u;
for(i=head1[u];i;i=edge[i].next){
int v=edge[i].to;
if(!vis[v]){
tarjan(v);
f[v]=u;
}
}
vis[u]=1;
for(i=head2[u];i;i=edge[i].next){
int v=edge[i].to;
if(vis[v]){
int t=find(v);
edge[++p].d=i;
edge[p].next=head3[t],head3[t]=p;
}
} //根据u,v的LCA分类
for(i=head3[u];i;i=edge[i].next){
int kk=edge[i].d;
int t=edge[kk].d,x=edge[kk].f,y=edge[kk].to;
find(x);
if(t<0){
int tem=x;
x=y,y=tem;
t=-t;
}
ans[t]=max(max(up[x],down[y]),mx[y]-mi[x]);
}
}
int main(){
int i,j,m;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&num[i]);
mi[i]=mx[i]=num[i];
up[i]=0,down[i]=0;
}
memset(head1,0,sizeof(head1));
memset(head2,0,sizeof(head2));
memset(vis,0,sizeof(vis));
for(i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
edge[++p].to=v;
edge[p].next=head1[u],head1[u]=p;
}
scanf("%d",&m);
for(i=1;i<=m;i++){
int u,v;
scanf("%d %d",&u,&v);
edge[++p].to=v;
edge[p].f=u,edge[p].d=i,edge[p].next=head2[u],head2[u]=p;
edge[++p].to=u;
edge[p].f=v,edge[p].d=-i,edge[p].next=head2[v],head2[v]=p;
}
tarjan(1);
for(i=1;i<=m;i++){
printf("%d\n",ans[i]);
}
}