树链剖分 给每一个信仰开一棵线段树
然后就是动态开点的打码问题了
#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;
}