题解:
正常的树链剖分,但由于颜色的限制,不能只开一棵线段树,我们可以对每个颜色都开一棵线段树,但这样空间不行,我们只要建实时开点线段树,就可以了。
对于询问,只要在那个颜色的线段树上询问就好了。
Code:
C
o
d
e
:
#include<iostream>
#include<cstdio>
#include<cstring>
#define M 10000005
#define N 100005
using namespace std;
int n,m,cnt,place,size;
int s[17],w[N],c[N],root[N],fa[N][17],deep[N],vis[N];
int pl[N],belong[N],son[N],head[N],ls[M],rs[M],mx[M],sum[M];
struct data
{
int vet,next;
}edge[N*2];
void ins(int u,int v)
{
edge[++cnt].vet=v;
edge[cnt].next=head[u];
head[u]=cnt;
}
void dfs1(int x)
{
vis[x]=1;son[x]=1;
for(int i=1;i<=16;i++)
if(s[i]<=deep[x])fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
for(int i=head[x];i;i=edge[i].next)
{
int v=edge[i].vet;
if(vis[v])continue;
deep[v]=deep[x]+1;
fa[v][0]=x;
dfs1(v);
son[x]+=son[v];
}
}
void dfs2(int x,int chain)
{
place++;
pl[x]=place;
belong[x]=chain;
int k=0;
for(int i=head[x];i;i=edge[i].next)
{
int v=edge[i].vet;
if(deep[v]>deep[x]&&son[v]>son[k])
k=v;
}
if(k)dfs2(k,chain);
for(int i=head[x];i;i=edge[i].next)
{
int v=edge[i].vet;
if(deep[v]>deep[x]&&v!=k)
dfs2(v,v);
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;i<=16;i++)
if(s[i]&t)x=fa[x][i];
for(int i=16;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if(x==y)return x;
return fa[x][0];
}
void change(int &k,int l,int r,int x,int num)
{
if(!k)k=++size;
if(l==r)
{
mx[k]=sum[k]=num;
return;
}
int mid=(l+r)>>1;
if(x<=mid)change(ls[k],l,mid,x,num);else
change(rs[k],mid+1,r,x,num);
mx[k]=max(mx[ls[k]],mx[rs[k]]);
sum[k]=sum[ls[k]]+sum[rs[k]];
}
int askmx(int k,int l,int r,int x,int y)
{
if(!k)return 0;
if(l==x&&y==r)return mx[k];
int mid=(l+r)>>1;
if(y<=mid)return askmx(ls[k],l,mid,x,y);else
if(x>mid)return askmx(rs[k],mid+1,r,x,y);else
return max(askmx(ls[k],l,mid,x,mid),askmx(rs[k],mid+1,r,mid+1,y));
}
int asksum(int k,int l,int r,int x,int y)
{
if(!k)return 0;
if(l==x&&y==r)return sum[k];
int mid=(l+r)>>1;
if(y<=mid)return asksum(ls[k],l,mid,x,y);else
if(x>mid)return asksum(rs[k],mid+1,r,x,y);else
return asksum(ls[k],l,mid,x,mid)+asksum(rs[k],mid+1,r,mid+1,y);
}
int solvemx(int c,int x,int f)
{
int mx=0;
while(belong[x]!=belong[f])
{
mx=max(mx,askmx(root[c],1,n,pl[belong[x]],pl[x]));
x=fa[belong[x]][0];
}
mx=max(mx,askmx(root[c],1,n,pl[f],pl[x]));
return mx;
}
int solvesum(int c,int x,int f)
{
int sum=0;
while(belong[x]!=belong[f])
{
sum+=asksum(root[c],1,n,pl[belong[x]],pl[x]);
x=fa[belong[x]][0];
}
sum+=asksum(root[c],1,n,pl[f],pl[x]);
return sum;
}
int main()
{
s[0]=1;
for(int i=1;i<=16;i++)
s[i]=(s[i-1]<<1);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&c[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
ins(u,v);
}
dfs1(1);dfs2(1,1);
for(int i=1;i<=n;i++)
change(root[c[i]],1,n,pl[i],w[i]);
for(int i=1;i<=m;i++)
{
char ch[5];scanf("%s",ch);
int x,y;
scanf("%d%d",&x,&y);
if(ch[0]=='C')
{
if(ch[1]=='C')
{
change(root[c[x]],1,n,pl[x],0);
c[x]=y;
change(root[c[x]],1,n,pl[x],w[x]);
}else
{
change(root[c[x]],1,n,pl[x],y);
w[x]=y;
}
}else
{
int f=lca(x,y);
if(ch[1]=='S')
{
int t=solvesum(c[x],x,f)+solvesum(c[x],y,f);
if(c[x]==c[f])t-=w[f];
printf("%d\n",t);
}else
printf("%d\n",max(solvemx(c[x],x,f),solvemx(c[x],y,f)));
}
}
return 0;
}