思路

以树链剖分+主席树可解决。 要动态开点(不然的话肯定会爆啊) 然后就是对每种颜色(宗教)为根的树进行单点修改还有区间查询。 注:这道题容易被卡常,我宏定义就写炸了很多次。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7;

vector<int>G[N];
inline void addedge(int u,int v){
	G[u].push_back(v);
	G[v].push_back(u);
}

int sz[N],fa[N],son[N],dep[N],dfn[N],idfn[N],bel[N],idx;

inline void dfs1(int x){
	sz[x]=1;
	for(int i=0;i<G[x].size();i++){
		int to=G[x][i];
		if(to==fa[x]) continue;
		fa[to]=x;
		dep[to]=dep[x]+1;
		dfs1(to);
		sz[x]+=sz[to];
		if(sz[son[x]]<sz[to]) son[x]=to;
	}
}

inline void dfs2(int x,int tp){
	dfn[x]=++idx;
	idfn[idx]=x;
	bel[x]=tp;
	if(son[x]) dfs2(son[x],tp);
	for(int i=0;i<G[x].size();i++){
		int to=G[x][i];
		if(to==son[x]||to==fa[x]) continue;
		dfs2(to,to); 
	}
}

#define ls tr[p].lson
#define rs tr[p].rson
#define MID int mid=l+r>>1

int rt[N],SZ;
struct node{
	int lson,rson,mx,sum;
}tr[N*24];

inline void pushup(int p){
	tr[p].sum=tr[ls].sum+tr[rs].sum;
	tr[p].mx=max(tr[ls].mx,tr[rs].mx);
}

inline void build(int &p,int l,int r,int pos,int val){
	if(!p) p=++SZ;
	if(l==r){
		tr[p].mx=tr[p].sum=val;
		return;
	}
	MID;
	if(pos<=mid) build(ls,l,mid,pos,val);
	else build(rs,mid+1,r,pos,val);
	pushup(p);
}

inline void del(int &p,int l,int r,int pos){
	if(l==r){
		tr[p].mx=tr[p].sum=p=0;
		return;
	} 
	MID;
	if(pos<=mid) del(ls,l,mid,pos);
	else del(rs,mid+1,r,pos);
	pushup(p);
	if(!ls&&!rs) tr[p].mx=tr[p].sum=p=0;
}

inline int qs(int &p,int l,int r,int ql,int qr){
	if(!p) return 0;
	if(ql<=l&&r<=qr) return tr[p].sum;
	MID;int res=0;
	if(ql<=mid) res=qs(ls,l,mid,ql,qr);
	if(qr>mid) res+=qs(rs,mid+1,r,ql,qr);
	return res;
}

inline int qm(int &p,int l,int r,int ql,int qr){
	if(!p) return 0;
	if(ql<=l&&r<=qr) return tr[p].mx; 
	MID;int res=0;
	if(ql<=mid) res=qm(ls,l,mid,ql,qr);
	if(qr>mid) res=max(res,qm(rs,mid+1,r,ql,qr));
	return res; 
}

int n,m,x,y,res,rd,tmp,val[N],col[N];
string op;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>val[i]>>col[i];
	for(int i=1;i<n;i++){
		cin>>x>>y;
		addedge(x,rd=y); //随机根节点 
	}
	dfs1(rd);
	dfs2(rd,rd);
	for(int i=1;i<=n;i++) build(rt[col[idfn[i]]],1,n,i,val[idfn[i]]);
	for(int i=1;i<=m;i++){
		cin>>op>>x>>y;
		if(op=="CC"){
			del(rt[col[x]],1,n,dfn[x]);
			col[x]=y;
			build(rt[col[x]],1,n,dfn[x],val[x]); 
		}else if(op=="CW"){
			del(rt[col[x]],1,n,dfn[x]);
			val[x]=y;
			build(rt[col[x]],1,n,dfn[x],val[x]);
		}else if(op=="QS"){
			res=0;
			tmp=col[x];
			while(bel[x]!=bel[y]){
				if(dep[bel[x]]<dep[bel[y]]) swap(x,y);
				res+=qs(rt[tmp],1,n,dfn[bel[x]],dfn[x]);
				x=fa[bel[x]];
			}
			if(dep[x]<dep[y]) swap(x,y);
			res+=qs(rt[tmp],1,n,dfn[y],dfn[x]);
			cout<<res<<"\n";
		}else{
			res=0;
			tmp=col[x];
			while(bel[x]!=bel[y]){
				if(dep[bel[x]]<dep[bel[y]]) swap(x,y);
				res=max(res,qm(rt[tmp],1,n,dfn[bel[x]],dfn[x]));
				x=fa[bel[x]];
			}
			if(dep[x]<dep[y]) swap(x,y);
			res=max(res,qm(rt[tmp],1,n,dfn[y],dfn[x]));
			cout<<res<<"\n";
		}
	}
	return 0;
}