 /**//*
题意:给出一棵节点有值的树,给出Q个询问(a,b),问从a到b的最大盈利(即:先在最小值买入,再在最大值卖出)
我有想过用一个新序列w2-w1 , w3-w2 , , wn-wn-1
这样只需用O(n)求得最大子段和即为结果Max-Min了
但Q很大,每次都找一个路径会超时
用类似Tarjan算法进行处理,但在find()那里要修改一下
对每个几点记录4个值
up[v] 表示从v到目前的根的最大盈利
down[v] 从目前的根到v的最大盈利
Max[v]表示到目前的根的最大值
Min[v]表示到目前的根的最小值
转移看update!
在LCA(u,v)处再来计算,这样那四个值才是正确的值!!
*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>

using namespace std;

 inline int min(int a,int b) {return a<b?a:b;}
 inline int max(int a,int b) {return a>b?a:b;}

const int MAXN = 50005;

struct Node
  {
int w,next;
}nodes[MAXN*4];

struct NodeQ
  {
int u,v,id,next;
}nodeqs[MAXN*2];

int Min[MAXN],Max[MAXN],down[MAXN],up[MAXN];
int fa[MAXN],w[MAXN],ans[MAXN];
int G[MAXN],Q[MAXN],D[MAXN];
bool vi[MAXN];
int N,K;
int allocq,alloc;

void addG(int a,int b)
  {
alloc++;
nodes[alloc].w=b,nodes[alloc].next=G[a];
G[a]=alloc;
}
void addQ(int a,int b,int id)
  {
allocq++;
nodeqs[allocq].u=a,nodeqs[allocq].v=b,nodeqs[allocq].id=id;
nodeqs[allocq].next=Q[a];Q[a]=allocq;
}
void addD(int a,int b)
  {
alloc++;
nodes[alloc].w=b;nodes[alloc].next=D[a];
D[a]=alloc;
}
 /**//*
Min[a] Max[a]
a -------> fa[a] --------> root
*/
void update(int x)
  {
 if(x!=fa[x]) {
update(fa[x]);//先处理好上面的
up[x]=max(up[x],max(up[fa[x]],Max[fa[x]]-Min[x]));//注意是Min[x],不是w[x],因为有路径压缩
down[x]=max(down[x],max(down[fa[x]],Max[x]-Min[fa[x]]));//同理是Max[x]
Max[x]=max(Max[x],Max[fa[x]]);
Min[x]=min(Min[x],Min[fa[x]]);
fa[x]=fa[fa[x]];
}
}
void Tarjan(int x)
  {
vi[x]=1;
 for(int son=Q[x];son;son=nodeqs[son].next) {
int v=nodeqs[son].v;
 if(vi[v]) {
update(v);
addD(fa[v],son);//保存u->lca->v的询问,然后在到达lca那里处理,这样那四个值才是正确的
}
}
 for(int son=G[x];son;son=nodes[son].next) {
int v=nodes[son].w;
 if(!vi[v]) {
Tarjan(v);
fa[v]=x;
}
}
 for(int son=D[x];son;son=nodes[son].next) {//lca为x,处理u,v
int u=nodeqs[nodes[son].w].u,v=nodeqs[nodes[son].w].v,id=nodeqs[nodes[son].w].id;
update(u);update(v);//u,v更新,lca会为x,因为fa[x]=x
 if(id<0) {id=-id;swap(u,v);}
ans[id]=max(up[u],down[v]);
ans[id]=max(ans[id],Max[v]-Min[u]);
}
}
int main()
  {
 while(~scanf("%d",&N)) {
memset(G+1,0,sizeof(int)*N);
memset(Q+1,0,sizeof(int)*N);
memset(D+1,0,sizeof(int)*N);
memset(up+1,0,sizeof(int)*N);
memset(down+1,0,sizeof(int)*N);
memset(ans+1,0,sizeof(int)*N);
memset(vi+1,0,sizeof(bool)*N);
alloc=allocq=0;
 for(int i=1;i<=N;i++) {
scanf("%d",&w[i]);
Max[i]=Min[i]=w[i];
fa[i]=i;
}
int a,b;
 for(int i=1;i<N;i++) {
scanf("%d%d",&a,&b);
addG(a,b);
addG(b,a);
}
scanf("%d",&K);
 for(int i=1;i<=K;i++) {
scanf("%d%d",&a,&b);
addQ(a,b,i);
addQ(b,a,-i);
}
Tarjan(1);
for(int i=1;i<=K;i++)
printf("%d\n",ans[i]);
}
return 0;
}

|