树链剖分 给每一个信仰开一棵线段树
然后就是动态开点的打码问题了
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define V G[p].v using namespace std; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(char *s){ char c=nc(); int len=0; for (;!(c>='A' && c<='Z');c=nc()); for (;c>='A' && c<='Z';s[++len]=c,c=nc()); s[++len]=0; } struct edge{ int u,v; int next; }; edge G[200005]; int head[100005],inum; inline void add(int u,int v,int p){ G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p; } int size[100005],fat[100005],depth[100005]; int clk,tid[100005],top[100005]; inline void dfs(int u,int fa) { fat[u]=fa; depth[u]=depth[fa]+1; size[u]=1; for (int p=head[u];p;p=G[p].next) if (V!=fa) dfs(V,u),size[u]+=size[V]; } inline void find (int u,int fa,int z) { tid[u]=++clk; top[u]=z; int maximum=0,son=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && size[V]>maximum) maximum=size[son=V]; if (son) find(son,u,z); for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son) find(V,u,V); } int n,Q; int w[100005],c[100005]; const int M=10000000; int Stack[M+5],pnt; int root[100005]; int ls[M+5],rs[M+5],sum[M+5],maxv[M+5]; inline void update(int x){ sum[x]=sum[ls[x]]+sum[rs[x]]; maxv[x]=max(maxv[ls[x]],maxv[rs[x]]); } inline void Init(){ for (int i=M;i;i--) Stack[++pnt]=i; } inline int New(){ return Stack[pnt--]; } inline void Del(int x){ if (x==0) return; sum[x]=maxv[x]=0; Stack[++pnt]=x; } inline int Sum(int &rt,int l,int r,int L,int R){ if (sum[rt]==0) return 0; int mid=(l+r)>>1; if (l==r) return sum[rt]; if (R<=mid) return Sum(ls[rt],l,mid,L,R); else if (L>mid) return Sum(rs[rt],mid+1,r,L,R); else return Sum(ls[rt],l,mid,L,mid)+Sum(rs[rt],mid+1,r,mid+1,R); } inline int Max(int &rt,int l,int r,int L,int R){ if (maxv[rt]==0) return 0; if (l==r) return maxv[rt]; int mid=(l+r)>>1; if (R<=mid) return Max(ls[rt],l,mid,L,R); else if (L>mid) return Max(rs[rt],mid+1,r,L,R); else return max(Max(ls[rt],l,mid,L,mid),Max(rs[rt],mid+1,r,mid+1,R)); } inline void Change(int &rt,int l,int r,int x,int val){ if (!rt) rt=New(); if (l==r) { sum[rt]=maxv[rt]=val; if (!sum[rt]) Del(rt),rt=0; return; } int mid=(l+r)>>1; if (x<=mid) Change(ls[rt],l,mid,x,val); else Change(rs[rt],mid+1,r,x,val); update(rt); if (!sum[rt]) Del(rt),rt=0; } inline int Qsum(int u,int v,int c){ int ret=0; for (;top[u]!=top[v];u=fat[top[u]]) { if (depth[top[u]]<depth[top[v]]) swap(u,v); ret+=Sum(root[c],1,n,tid[top[u]],tid[u]); } if (depth[u]>depth[v]) swap(u,v); ret+=Sum(root[c],1,n,tid[u],tid[v]); return ret; } inline int Qmax(int u,int v,int c){ int ret=0; for (;top[u]!=top[v];u=fat[top[u]]) { if (depth[top[u]]<depth[top[v]]) swap(u,v); ret=max(ret,Max(root[c],1,n,tid[top[u]],tid[u])); } if (depth[u]>depth[v]) swap(u,v); ret=max(ret,Max(root[c],1,n,tid[u],tid[v])); return ret; } inline void CC(int u,int x){ Change(root[c[u]],1,n,tid[u],0); c[u]=x; Change(root[c[u]],1,n,tid[u],w[u]); } inline void CW(int u,int x){ w[u]=x; Change(root[c[u]],1,n,tid[u],w[u]); } int main() { char order[5]; int iu,iv,ans; Init(); freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(Q); for (int i=1;i<=n;i++) read(w[i]),read(c[i]); for (int i=1;i<n;i++) read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum); dfs(1,0); find(1,0,1); for (int i=1;i<=n;i++) Change(root[c[i]],1,n,tid[i],w[i]); while (Q--) { read(order); read(iu); read(iv); if (!strcmp(order+1,"CC")) CC(iu,iv); else if (!strcmp(order+1,"CW")) CW(iu,iv); else if (!strcmp(order+1,"QS")) { ans=Qsum(iu,iv,c[iu]); printf("%d\n",ans); } else if (!strcmp(order+1,"QM")) { ans=Qmax(iu,iv,c[iu]); printf("%d\n",ans); } } return 0; }