[SDOI2011]染色
此题我就用刚刚学过的LCT解吧……
颓废了好几天终于学了一个数据结构,还不精通qwq……不看题解我还是挂啊……
废话不多说,讲题。
题目描述
输入输出格式
解:
既然用LCT做,那就分析一下思路。
题目中求颜色数,那就先考虑维护什么吧。
一个点,需要维护它的父亲,它的儿子,它本身的颜色,它左孩子的颜色,右孩子的颜色,翻转标记,覆盖标记以及它的区间的颜色数。
(好累啊qwq)
题目中提到了无向边,自然联想到Link操作。
一个LCT的影子出来了。
对于每次修改,写一个区间放覆盖标记的pushl函数。
对于询问,先将a到b的路径合并(split),这个过程中标记什么的自动下放,维护整体结构,以此保证复杂度。
接下来。直接输出b的num即可。
(每次讲的很简单写起来要累死qwq)
注意所有的标记下放,对于翻转标记,不仅翻转儿子,还要翻转颜色。
对于覆盖标记,全部下放一遍。
pushup会有些麻烦,注意好左右孩子颜色以及它的颜色段数量维护即可。
代码:
#include<cstdio> #include<iostream> using namespace std; struct node{ int ch[2],fa,lcol,rcol,col,rev,tag,num; }tr[500000]; inline void read(int &x){ int s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }x=s*w;return; }inline bool root(int x){ int g=tr[x].fa; return !(tr[g].ch[1]==x||tr[g].ch[0]==x); }inline void pushup(int x){ int l=tr[x].ch[0],r=tr[x].ch[1]; tr[x].lcol=l?tr[l].lcol:tr[x].col; tr[x].rcol=r?tr[r].rcol:tr[x].col; if(l&&r)tr[x].num=tr[l].num+tr[r].num+1-(tr[l].rcol==tr[x].col)-(tr[r].lcol==tr[x].col); else if(l)tr[x].num=tr[l].num+(tr[l].rcol!=tr[x].col); else if(r)tr[x].num=tr[r].num+(tr[r].lcol!=tr[x].col); else tr[x].num=1; }inline void pushr(int x){ if(!x)return; swap(tr[x].ch[0],tr[x].ch[1]); swap(tr[x].lcol,tr[x].rcol); tr[x].rev^=1; }inline void pushl(int x,int y){ tr[x].col=tr[x].lcol=tr[x].rcol=y; tr[x].num=1;tr[x].tag=y; }inline void pushdown(int x){ int l=tr[x].ch[0],r=tr[x].ch[1]; if(tr[x].tag){ pushl(l,tr[x].tag);pushl(r,tr[x].tag); tr[x].tag=0; }if(tr[x].rev){ pushr(l);pushr(r); tr[x].rev=0; } }inline void rotate(int x){ int y=tr[x].fa,z=tr[y].fa,k=tr[y].ch[1]==x; if(!root(y))tr[z].ch[tr[z].ch[1]==y]=x; tr[x].fa=z;tr[y].ch[k]=tr[x].ch[k^1]; if(tr[x].ch[k^1])tr[tr[x].ch[k^1]].fa=y; tr[y].fa=x;tr[x].ch[k^1]=y;pushup(y);pushup(x); }inline void pushrt(int x){ if(!root(x))pushrt(tr[x].fa); pushdown(x); }inline void splay(int x){ int y,z; pushrt(x); while(!root(x)){ y=tr[x].fa,z=tr[y].fa; if(!root(y))(tr[y].ch[1]==x)^(tr[z].ch[1]==y)?rotate(x):rotate(y); rotate(x); }pushup(x); }inline void access(int x){ for(int y=0;x;y=x,x=tr[x].fa){ splay(x);tr[x].ch[1]=y;pushup(x); } }inline void makeroot(int x){ access(x);splay(x);pushr(x); }inline void link(int x,int y){ makeroot(x);tr[x].fa=y; }inline void split(int x,int y){ makeroot(x);access(y);splay(y); }int n,m,a,b,c; char s[50]; int main(){ read(n);read(m); for(int i=1;i<=n;++i){ read(tr[i].col);tr[i].lcol=tr[i].rcol=tr[i].col;tr[i].num=1; }for(int i=1;i<n;++i){ read(a);read(b); link(a,b); }for(int i=1;i<=m;++i){ cin>>s;read(a);read(b); split(a,b); if(s[0]=='C'){ read(c);pushl(b,c); }else printf("%d\n",tr[b].num); }return 0; }