题目大意:
给出一棵树。每一个点有商店。每一个商店都有一个价格,Yaoge每次从x走到y都能够在一个倒卖商品,从中得取利益。当然,买一顶要在卖之前。可是没次走过一条路,这条路上的全部商品都会添加一个v。
输出每次的最大利益。
思路分析:
非常easy想到树链剖分,但是关键在于怎样维护这样一个变量。使得每次都要让买的再卖的前面。
维护变量 ltr 和 rtl 。表示从左去右和从右去左。
剖分熟练的时候。推断x 和 y的深度,一步一步往上爬。
然后维护区间最大值和最小值。爬的时候更新答案。
。。。4921ms...小孩子不要看。。。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #pragma comment(linker,"/STACk:10240000,10240000") #define maxn 50005 #define Inf 0x3FFFFFFFFFFFFFFFLL #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e using namespace std; typedef long long ll; int next[maxn<<1],to[maxn<<1],head[maxn],tot;//临界表 int pre[maxn],root[maxn],siz[maxn],son[maxn],w[maxn],dep[maxn],id;//原树的父亲 链上的根 siz 有最大siz的子树 又一次分配的id 深度 getid中来计数的 ll ltr[maxn<<2],rtl[maxn<<2],mx[maxn<<2],mn[maxn<<2],add[maxn<<2];//线段树变量 int n; void init() { pre[1]=0; dep[1]=0; tot=0;id=0; memset(head,0,sizeof head); memset(add,0,sizeof add); memset(mn,0,sizeof mn); memset(mx,0,sizeof mx); memset(ltr,0,sizeof ltr); memset(rtl,0,sizeof rtl); } void addedge(int u,int v) { tot++; next[tot]=head[u]; to[tot]=v; head[u]=tot; } void dfs(int now)//to get size,son,dep,pre... { son[now]=0; siz[now]=1; for(int p =head[now]; p ; p=next[p]) { int t=to[p]; if(t!=pre[now]) { pre[t]=now; dep[t]=dep[now]+1; dfs(t); if(siz[t]>siz[son[now]])son[now]=t; siz[now]+=siz[t]; } } } void getid(int now,int rt)//to get w and root... { w[now]=++id; root[now]=rt; if(son[now])getid(son[now],rt); for(int p = head[now] ; p ; p=next[p]) { int t=to[p]; if(t!=son[now]&&t!=pre[now]) getid(t,t); } } void pushdown(int num,int s,int e) { if(add[num]) { int mid=(s+e)>>1; mx[num<<1]+=add[num]; mx[num<<1|1]+=add[num]; mn[num<<1]+=add[num]; mn[num<<1|1]+=add[num]; add[num<<1]+=add[num]; add[num<<1|1]+=add[num]; add[num]=0; } } void pushup(int num) { mx[num]=max(mx[num<<1],mx[num<<1|1]); mn[num]=min(mn[num<<1],mn[num<<1|1]); ltr[num]=max(mx[num<<1|1]-mn[num<<1],max(ltr[num<<1],ltr[num<<1|1])); rtl[num]=max(mx[num<<1]-mn[num<<1|1],max(rtl[num<<1],rtl[num<<1|1])); if(ltr[num]<0)ltr[num]=0; if(rtl[num]<0)rtl[num]=0; } void update(int num,int s,int e,int l,int r,int val) { if(l<=s && r>=e) { add[num]+=val; mx[num]+=val; mn[num]+=val; return; } pushdown(num,s,e); int mid=(s+e)>>1; if(l<=mid)update(lson,l,r,val); if(r>mid)update(rson,l,r,val); pushup(num); } ll query(int num,int s,int e,int l,int r,int flg,ll &maxv,ll &minv) { if(l<=s && r>=e) { maxv=mx[num]; minv=mn[num]; if(flg)return ltr[num]; else return rtl[num]; } int mid=(s+e)>>1; pushdown(num,s,e); if(r<=mid)return query(lson,l,r,flg,maxv,minv); else if(l>mid)return query(rson,l,r,flg,maxv,minv); else { ll r1,r2,n1,n2,m1,m2,ans; r1=query(lson,l,mid,flg,m1,n1); r2=query(rson,mid+1,r,flg,m2,n2); maxv=max(m1,m2); minv=min(n1,n2); if(flg) { ans=max(r1,r2); ans=max(ans,m2-n1); } else { ans=max(r1,r2); ans=max(ans,m1-n2); } ans=max(0LL,ans); return ans; } } ll fuck(int x,int y) { ll ans=0,maxx,minx,maxy,miny,rx,ry; ll tmax,tmin,tr; maxx=maxy=0; minx=miny=Inf; rx=ry=0; while(root[x]!=root[y]) { if(dep[root[x]]<dep[root[y]]) { tr=query(1,1,n,w[root[y]],w[y],1,tmax,tmin); ry=max(ry,tr); ry=max(ry,maxy-tmin); maxy=max(maxy,tmax); miny=min(miny,tmin); ans=max(ans,ry); y=pre[root[y]]; } else { tr=query(1,1,n,w[root[x]],w[x],0,tmax,tmin); rx=max(rx,tr); rx=max(rx,tmax-minx); maxx=max(tmax,maxx); minx=min(tmin,minx); ans=max(ans,rx); x=pre[root[x]]; } } if(dep[x]<dep[y]) { tr=query(1,1,n,w[x],w[y],1,tmax,tmin); ans=max(ans,tr); ans=max(ans,maxy-tmin); maxy=max(tmax,maxy); miny=min(tmin,miny); ans=max(ans,maxy-minx); } else { tr=query(1,1,n,w[y],w[x],0,tmax,tmin); ans=max(ans,tr); ans=max(ans,tmax-minx); maxx=max(tmax,maxx); minx=min(tmin,minx); ans=max(ans,maxy-minx); } return ans; } void work(int x,int y,int val) { while(root[x]!=root[y]) { if(dep[root[x]]<dep[root[y]])swap(x,y); update(1,1,n,w[root[x]],w[x],val); x=pre[root[x]]; } if(dep[x]>dep[y])swap(x,y); update(1,1,n,w[x],w[y],val); } int save[maxn]; inline void scanf_(int &num){ char in; bool neg=false; while(((in=getchar()) > '9' || in<'0') && in!='-') ; if(in=='-'){ neg=true; while((in=getchar()) >'9' || in<'0'); } num=in-'0'; while(in=getchar(),in>='0'&&in<='9') num*=10,num+=in-'0'; if(neg) num=0-num; } inline void printf_(ll num){ bool flag=false; if(num<0){ putchar('-'); num=-num; } int ans[20],top=0; while(num!=0){ ans[top++]=num%10; num/=10; } if(top==0) putchar('0'); for(int i=top-1;i>=0;i--){ char ch=ans[i]+'0'; putchar(ch); } puts(""); } int main() { int T; scanf_(T); while(T--) { init(); scanf_(n); for(int i=1;i<=n;i++) scanf_(save[i]); for(int i=1;i<=n-1;i++) { int s,e; scanf_(s);scanf_(e); addedge(s,e); addedge(e,s); } dfs(1); getid(1,1); for(int i=1;i<=n;i++) update(1,1,n,w[i],w[i],save[i]); char str[5]; int Q; scanf_(Q); while(Q--) { int x,y,v; scanf_(x); scanf_(y); scanf_(v); printf_(fuck(x,y)); work(x,y,v); } } return 0; }