题意:给出一颗树,每个节点的商品价值可能不同,有Q个查询,每个查询,每个查询(u,v)表示一个人从u走到v,他可以再某个经过的节点中买一个商品,然后在之后的路径中找到一个节点把这个商品卖掉,求能获得的最大利润。走完路径后,这条路径的商品价值都 + V。
思路:不会写lct的我只好去写树链剖分了。。。。这题比赛的时候都写傻了,非常艰辛的调过去了,以前觉得这种题比赛的时候肯定是写不出来的,最近两场网赛都有,还都写出来了,真是感动。。。其实思路还好,把重链搞出来以后线段树维护就行了,线段树中记录的是最大价值,区间最大值和区间最小值,由于这条路径是有向的,因此,写了两个方向的结果,一个是从左到右,一个是从右到左。某一个区间和结果要么等于下面两个区间结果的最大值,要么等于左区间的最大值减右区间最小值(向左走,向右走同理)。然后注意一下方向就可以做了……
代码:
#pragma comment(linker,"/STACK:100000000,100000000") #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<set> #include<cmath> #include<vector> #include<bitset> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-6 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn = 50000 + 10; struct Edge { int v,next; Edge(int v = 0,int next = 0):v(v),next(next){} }edges[maxn<<1]; int d[maxn],pa[maxn],fp[maxn],vson[maxn],val[maxn]; int head[maxn],id[maxn],convert[maxn],nEdge,N; void AddEdges(int u,int v) { edges[++nEdge] = Edge(v,head[u]); head[u] = nEdge; edges[++nEdge] = Edge(u,head[v]); head[v] = nEdge; } int dfs(int u,int fa) { int csum=1,cmax=0,me=-1; for(int k=head[u];k!=-1;k=edges[k].next) { int v=edges[k].v; if(v==fa) continue; d[v]=d[u]+1;pa[v]=u; int cc=dfs(v,u); csum+=cc; if(cc>cmax) {cmax=cc;me=v;} } vson[u]=me; return csum; } void dfs2(int u,int fa) { if(vson[u]!=-1) { id[u]=++N; convert[N] = u; if(fa==-1||vson[fa]!=u) fp[u]=u; else fp[u]=fp[fa]; dfs2(vson[u],u); } else if(fa==-1||vson[fa]==u) id[u]=++N,convert[N] = u,fp[u]=(fa==-1)?u:fp[fa]; for(int k=head[u];k!=-1;k=edges[k].next) { int v=edges[k].v; if(v==fa||v==vson[u]) continue; fp[v]=v; if(vson[v] == -1) { id[v] = ++N; convert[N] = v; } dfs2(v,u); } } struct SegTree { ll maxv[maxn<<2],minv[maxn<<2],mxp[maxn<<2][2],addv[maxn<<2]; void PushUp(int rt) { maxv[rt] = max(maxv[rt<<1],maxv[rt<<1|1]); minv[rt] = min(minv[rt<<1],minv[rt<<1|1]); mxp[rt][0] = max(mxp[rt<<1][0],mxp[rt<<1|1][0]); mxp[rt][0] = max(mxp[rt][0],maxv[rt<<1] - minv[rt<<1|1]); if(mxp[rt][0] < 0) mxp[rt][0] = 0; mxp[rt][1] = max(mxp[rt<<1][1],mxp[rt<<1|1][1]); mxp[rt][1] = max(mxp[rt][1],maxv[rt<<1|1] - minv[rt<<1]); if(mxp[rt][1] < 0) mxp[rt][1] = 0; } void PushDown(int rt) { if(addv[rt]) { addv[rt<<1] += addv[rt]; addv[rt<<1|1] += addv[rt]; maxv[rt<<1] += addv[rt]; maxv[rt<<1|1] += addv[rt]; minv[rt<<1] += addv[rt]; minv[rt<<1|1] += addv[rt]; addv[rt] = 0; } } void build(int l,int r,int rt) { addv[rt] = 0; if(l == r) { maxv[rt] = minv[rt] = val[convert[l]]; mxp[rt][0] = mxp[rt][1] = 0; return ; } int m = (l + r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(rt); } void Update(int L,int R,int l,int r,int rt,int v) { if(l >= L && r <= R) { addv[rt] += v; minv[rt] += v; maxv[rt] += v; return ; } PushDown(rt); int m = (l + r)>>1; if(m >= L) Update(L,R,l,m,rt<<1,v); if(m < R) Update(L,R,m+1,r,rt<<1|1,v); PushUp(rt); } ll Query(int L,int R,int l,int r,int rt,int type,ll & mx,ll & mn) { if(l >= L && r <= R) { mx = maxv[rt]; mn = minv[rt]; return mxp[rt][type]; } PushDown(rt); int m = (l + r)>>1; if(m >= R) return Query(L,R,l,m,rt<<1,type,mx,mn); else if(m < L) return Query(L,R,m+1,r,rt<<1|1,type,mx,mn); else { ll r1,r2,m1,m2,n1,n2; r1 = Query(L,R,l,m,rt<<1,type,m1,n1); r2 = Query(L,R,m+1,r,rt<<1|1,type,m2,n2); mx = max(m1,m2); mn = min(n1,n2); if(type == 0) { r1 = max(r1,r2); r1 = max(r1,m1 - n2); } else { r1 = max(r1,r2); r1 = max(r1,m2 - n1); } if(r1 < 0) r1 = 0; return r1; } } }tree; void Init() { memset(head,0xff,sizeof(head)); memset(d,0,sizeof(d)); memset(vson,0xff,sizeof(vson)); memset(id,0xff,sizeof(id)); nEdge=-1;N=0; } void ADD(int x,int y,int c) { while(fp[x]!=fp[y]) { if(d[fp[x]]<d[fp[y]]) { swap(x,y); } tree.Update(id[fp[x]],id[x],1,N,1,c); x=pa[fp[x]]; } if(d[x]<d[y]) { swap(x,y); } tree.Update(id[y],id[x],1,N,1,c); } ll getMaxp(int x,int y) { //x -> y ll ans = 0,maxx,minx,maxy,miny,rx,ry; ll tmax,tmin,tr; rx = ry = 0; maxx = maxy = 0; minx = miny = Inf; while(fp[x] != fp[y]) { if(d[fp[x]] < d[fp[y]]) { tr = tree.Query(id[fp[y]],id[y],1,N,1,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 = pa[fp[y]]; } else { tr = tree.Query(id[fp[x]],id[x],1,N,1,0,tmax,tmin); rx = max(rx,tr); rx = max(rx,tmax - minx); maxx = max(maxx,tmax); minx = min(minx,tmin); ans = max(ans,rx); x = pa[fp[x]]; } } if(d[x] < d[y]) { if(id[x] > id[y]) while(true); tr = tree.Query(id[x],id[y],1,N,1,1,tmax,tmin); ans = max(ans,tr); ans = max(ans,maxy - tmin); maxy = max(maxy,tmax); miny = min(miny,tmin); ans = max(ans,maxy - minx); } else { // if(id[y] > id[x]) while(true); tr = tree.Query(id[y],id[x],1,N,1,0,tmax,tmin); ans = max(ans,tr); ans = max(ans,tmax - minx); maxx = max(maxx,tmax); minx = min(minx,tmin); ans = max(ans,maxy - minx); } return ans; //////////////////////////// } void reads(int & x) { char c; bool neg=false; while(((c=getchar())<'0'||c>'9')&&c!='-'); if(c=='-') { neg=true; while((c=getchar())<'0'||c>'9'); } x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0'; if(neg) x=-x; } void outs(ll num) { 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); } putchar('\n'); } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); int t; scanf("%d",&t); while(t--) { Init(); int n,m,u,v,w; reads(n); for(int i = 1;i <= n;++i) reads(val[i]); for(int i = 1;i < n;++i) { reads(u);reads(v); AddEdges(u,v); } dfs(1,-1); dfs2(1,-1); tree.build(1,N,1); reads(m); ll ans; while(m--) { reads(u);reads(v);reads(w); ans = getMaxp(u,v); outs(ans); ADD(u,v,w); } } return 0; }