题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531
题意:给出一棵树,每个节点有两个属性(x,y)。(1)改变某个节点的x属性或y属性;(2)从s到t,输出中间节点与s节点y属性相同的所有节点的x属性的和或最大值。
思路:树链剖分。之后是线段树维护。难操作的是这里有个y属性。T[y]表示y属性的根,有多少种y属性有多少个线段树。
struct node { i64 sum,Max; int L,R; }; int top[N],pos[N],b[N],cnt; int W[N],C[N]; node a[N*40]; int e; int T[N]; int n; void pushUp(int t) { a[t].sum=a[a[t].L].sum+a[a[t].R].sum; a[t].Max=max(a[a[t].L].Max,a[a[t].R].Max); } void build(int L,int R,int pos,int val,int &t) { if(!t) t=++e,a[t].L=a[t].R=0; if(L==R) { a[t].sum=a[t].Max=val; return; } int mid=(L+R)>>1; if(pos<=mid) build(L,mid,pos,val,a[t].L); else build(mid+1,R,pos,val,a[t].R); pushUp(t); } void changeType(int x,int c) { if(c==C[x]) return; int p=pos[x]; build(1,n,p,0,T[C[x]]); C[x]=c; build(1,n,p,W[x],T[C[x]]); } void changeVal(int x,int w) { if(w==W[x]) return; int p=pos[x]; W[x]=w; build(1,n,p,W[x],T[C[x]]); } i64 querySum(int L,int R,int ll,int rr,int t) { if(!t) return 0; if(ll==L&&rr==R) return a[t].sum; int mid=(L+R)>>1; if(rr<=mid) return querySum(L,mid,ll,rr,a[t].L); if(ll>mid) return querySum(mid+1,R,ll,rr,a[t].R); return querySum(L,mid,ll,mid,a[t].L)+querySum(mid+1,R,mid+1,rr,a[t].R); } i64 queryMax(int L,int R,int ll,int rr,int t) { if(!t) return 0; if(ll==L&&rr==R) return a[t].Max; int mid=(L+R)>>1; if(rr<=mid) return queryMax(L,mid,ll,rr,a[t].L); if(ll>mid) return queryMax(mid+1,R,ll,rr,a[t].R); i64 x=queryMax(L,mid,ll,mid,a[t].L); i64 y=queryMax(mid+1,R,mid+1,rr,a[t].R); return max(x,y); } vector<int> g[N]; int size[N]; int m; int isOnSameChain(int x,int y) { return top[x]==top[y]; } int getTop(int x) { return top[x]; } int dep[N]; int f[N]; void calSum(int x,int y) { i64 ans=0; int type=C[x]; while(!isOnSameChain(x,y)) { int top1=getTop(x); int top2=getTop(y); if(dep[top1]<dep[top2]) swap(top1,top2),swap(x,y); ans+=querySum(1,n,pos[top1],pos[x],T[type]); x=f[top1]; } if(pos[x]>pos[y]) swap(x,y); ans+=querySum(1,n,pos[x],pos[y],T[type]); printf("%lld\n",ans); } void calMax(int x,int y) { i64 ans=0; int type=C[x]; while(!isOnSameChain(x,y)) { int top1=getTop(x); int top2=getTop(y); if(dep[top1]<dep[top2]) swap(top1,top2),swap(x,y); i64 tmp=queryMax(1,n,pos[top1],pos[x],T[type]); upMax(ans,tmp); x=f[top1]; } if(pos[x]>pos[y]) swap(x,y); i64 tmp=queryMax(1,n,pos[x],pos[y],T[type]); upMax(ans,tmp); printf("%lld\n",ans); } int son[N]; void DFS(int u,int pre) { f[u]=pre; dep[u]=dep[pre]+1; size[u]=1; son[u]=0; int i,v,Max=0,t=0; FOR0(i,SZ(g[u])) { v=g[u][i]; if(v==pre) continue; DFS(v,u); size[u]+=size[v]; if(Max<size[v]) Max=size[v],t=v; } son[u]=t; } void DFS1(int u,int pre,int root) { top[u]=root; cnt++; pos[u]=cnt; b[cnt]=u; if(son[u]) { DFS1(son[u],u,root); int i,v; FOR0(i,SZ(g[u])) { v=g[u][i]; if(v==pre||v==son[u]) continue; DFS1(v,u,v); } } } int main() { RD(n,m); int i,x,y,z; FOR1(i,n) RD(W[i],C[i]); FOR1(i,n-1) { RD(x,y); g[x].pb(y); g[y].pb(x); } DFS(1,0); DFS1(1,0,1); for(i=1;i<=n;i++) build(1,n,pos[i],W[i],T[C[i]]); char op[10]; while(m--) { RD(op); RD(x,y); if(op[0]=='C'&&op[1]=='C') { changeType(x,y); } else if(op[0]=='C'&&op[1]=='W') { changeVal(x,y); } else if(op[0]=='Q'&&op[1]=='S') { calSum(x,y); } else { calMax(x,y); } } }