很经典的一道题目,这里介绍LCT的做法。
对splay的每个结点维护当前以该结点为根的子树内第一个结点和最后一个结点(即对应区间两端)的颜色,以及该子树内颜色段数。pushup合并的时候,如果合并的两个区间相邻部分的颜色不同,新区间的颜色段数就是两个区间的和,如果相同就-1。修改就打lazy标记。注意打标记要同时更新,不能等pushdown再更新。另外翻转的时候还要交换区间两端颜色。
似乎树剖更好写?
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m;
inline int read(){
int ret=0,sign=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') sign=-1;
if(ch=='C'||ch=='Q') return ch;
ch=getchar();
}
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*sign;
}
int fa[maxn],son[maxn][2],c0[maxn],c[maxn][2],sum[maxn],rev[maxn],tag[maxn];
inline bool isroot(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
inline int getson(int u){return son[fa[u]][1]==u;}
inline void pushup(int u){
sum[u]=1,c[u][0]=c[u][1]=c0[u];
if(son[u][0]) sum[u]+=c0[u]==c[son[u][0]][1]?sum[son[u][0]]-1:sum[son[u][0]],c[u][0]=c[son[u][0]][0];
if(son[u][1]) sum[u]+=c0[u]==c[son[u][1]][0]?sum[son[u][1]]-1:sum[son[u][1]],c[u][1]=c[son[u][1]][1];
}
inline void Rev(int u){rev[u]^=1,swap(son[u][0],son[u][1]),swap(c[u][0],c[u][1]);}
inline void modify(int u,int x){tag[u]=c0[u]=c[u][0]=c[u][1]=x,sum[u]=1;}
inline void pushdown(int u){
if(rev[u]){
rev[u]=0;
if(son[u][0]) Rev(son[u][0]);
if(son[u][1]) Rev(son[u][1]);
}
if(tag[u]){
if(son[u][0]) modify(son[u][0],tag[u]);
if(son[u][1]) modify(son[u][1],tag[u]);
tag[u]=0;
}
}
inline void rotate(int u){
int v=fa[u],rela=getson(u);
fa[u]=fa[v]; if(!isroot(v)) son[fa[v]][getson(v)]=u;
son[v][rela]=son[u][rela^1]; if(son[u][rela^1]) fa[son[u][rela^1]]=v;
fa[v]=u,son[u][rela^1]=v;
pushup(v),pushup(u);
}
int S[maxn],top;
inline void splay(int u){
S[top=1]=u;
for(int t=u;!isroot(t);t=fa[t]) S[++top]=fa[t];
while(top) pushdown(S[top--]);
while(!isroot(u)){
int v=fa[u];
if(!isroot(v)) rotate(getson(u)==getson(v)?v:u);
rotate(u);
}
}
inline void access(int u){for(int v=0;u;v=u,u=fa[u]) splay(u),son[u][1]=v,pushup(u);}
inline void makeroot(int u){access(u),splay(u),Rev(u);}
inline void split(int u,int v){makeroot(u),access(v),splay(v);}
inline void link(int u,int v){makeroot(u),fa[u]=v;}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) c0[i]=c[i][0]=c[i][1]=read(),sum[i]=1;
for(int i=1;i<n;i++) link(read(),read());
for(int i=1;i<=m;i++){
int op=read(),a=read(),b=read(),_c;
split(a,b);
if(op=='C') _c=read(),modify(b,_c);
else printf("%d\n",sum[b]);
}
return 0;
}