这题如果直接做,显然是是对每个信仰维护一棵线段树,但是这样铁定炸内存,因此考虑使用动态开点线段树
这样的答案就和询问的个数相关。之后就是普通的树链剖分维护
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pll; const int N=2e5+10; const int M=2e6+10; const int inf=0x3f3f3f3f; const ll mod=998244353; int id[N],w[N],dfn[N],top[N],h[N],e[N],ne[N],idx,times; int fa[N],sz[N],son[N],depth[N],rt[N]; int c[N]; int tot,n; ll ans; struct node{ int l,r; int sum; int mx; }tr[N*24]; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs(int u){//算父亲和重儿子 int i; sz[u]=1; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa[u]) continue; fa[j]=u; depth[j]=depth[u]+1; dfs(j); sz[u]+=sz[j]; if(sz[j]>sz[son[u]]){ son[u]=j; } } } void dfs1(int u,int x){ dfn[u]=++times; id[times]=u; top[u]=x; if(!son[u]) return ; dfs1(son[u],x); for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==son[u]||j==fa[u]) continue; dfs1(j,j); } } void pushup(int u){ int l=tr[u].l,r=tr[u].r; tr[u].mx=max(tr[l].mx,tr[r].mx); tr[u].sum=tr[l].sum+tr[r].sum; } void pushdown(int u){ tr[u].mx=tr[u].sum=0; } void modify(int &u,int x,int l,int r,int v){ if(!u) u=++tot; if(l==r){ tr[u].sum=tr[u].mx=v; return ; } int mid=l+r>>1; if(x<=mid) modify(tr[u].l,x,l,mid,v); else modify(tr[u].r,x,mid+1,r,v); pushup(u); } void del(int &u,int x,int l,int r){ if(!u) return ; if(l==r){ pushdown(u); u=0; return ; } int mid=l+r>>1; if(x<=mid) del(tr[u].l,x,l,mid); else del(tr[u].r,x,mid+1,r); pushup(u); } ll query_sum(int &u,int L,int R,int l,int r){ if(!u) return 0; if(L<=l&&r<=R){ return tr[u].sum; } ll ans=0; int mid=l+r>>1; if(L<=mid) ans+=query_sum(tr[u].l,L,R,l,mid); if(R>mid) ans+=query_sum(tr[u].r,L,R,mid+1,r); return ans; } ll query_mx(int &u,int L,int R,int l,int r){ if(!u) return 0; if(L<=l&&r<=R){ return tr[u].mx; } ll ans=0; int mid=l+r>>1; if(L<=mid) ans=max(ans,query_mx(tr[u].l,L,R,l,mid)); if(R>mid) ans=max(ans,query_mx(tr[u].r,L,R,mid+1,r)); return ans; } int main(){ ios::sync_with_stdio(false); int q; cin>>n>>q; int i; memset(h,-1,sizeof h); for(i=1;i<=n;i++) cin>>w[i]>>c[i]; for(i=1;i<n;i++){ int a,b; cin>>a>>b; add(a,b); add(b,a); } dfs(1); dfs1(1,1); for(i=1;i<=n;i++){ modify(rt[c[id[i]]],i,1,n,w[id[i]]); } string s; while(q--){ cin>>s; int x,y; if(s[1]=='C'){ cin>>x>>y; del(rt[c[x]],dfn[x],1,n); c[x]=y; modify(rt[c[x]],dfn[x],1,n,w[x]); } if(s[1]=='W'){ cin>>x>>y; del(rt[c[x]],dfn[x],1,n); w[x]=y; modify(rt[c[x]],dfn[x],1,n,w[x]); } if(s[1]=='S'){ cin>>x>>y; int k=c[x]; ans=0; while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]]) swap(x,y); ans+=query_sum(rt[k],dfn[top[x]],dfn[x],1,n); x=fa[top[x]]; } if(depth[x]>depth[y]) swap(x,y); ans+=query_sum(rt[k],dfn[x],dfn[y],1,n); cout<<ans<<endl; } if(s[1]=='M'){ cin>>x>>y; int k=c[x]; ans=0; while(top[x]!=top[y]){ if(depth[top[x]]<depth[top[y]]) swap(x,y); ans=max(ans,query_mx(rt[k],dfn[top[x]],dfn[x],1,n)); x=fa[top[x]]; } if(depth[x]>depth[y]) swap(x,y); ans=max(ans,query_mx(rt[k],dfn[x],dfn[y],1,n)); cout<<ans<<endl; } } return 0; }