/**//* 题意:给出一棵节点有值的树,给出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; }
|