[SDOI2011]染色
题目:染色
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2243
分析:
(1)很裸的树链剖分,然而我忘了树剖怎么打(其实是代码太长不想打,逃
(2)于是挖了一个大坑,把自己埋下去了(全世界是不是只有我傻傻打了LCT?
(3)卡卡OJ竟然过了,数据太弱了好慌。
(4)LCT好像没有什么细节(也不知道是谁调了一晚上
(5)简单说一下变量
num[x](SplayTree中x所控制的子树中颜色段数量)
lc[x](SplayTree中x所控制的子树中最左边的点的颜色)
rc[x](SplayTree中x所控制的子树中最右边的点的颜色)
vc[x](x点本身的颜色)
tag[x](lazy_tag标记)
rev[x](LCT专用翻转标记)
(6)简单说一下更新操作(Up operation)
num[x] : num[x]=(IF exist left_tree)num[ls[x][0]]-(rc[ls[x][0]]==vc[x])+(IF exist right_tree)num[ls[x][1]]-(lc[tr]==vc[x])+1;
lc[x] : IF (exist left_tree) lc[x]=lc[ls[x][0]] ELSE lc[x]=vc[x];
rc[x] : IF (exist right_tree) rc[x]=rc[ls[x][0]] ELSE rc[x]=vc[x];
(7)简单说一下下传操作 ( Down operation )
IF(exist rev operation):
IF(exist left_tree)rev[ls[x][0]]^=1;
IF(exist right_tree)rev[ls[x][1]]^=1;
clear rev[x];
swap(left_tree,right_tree);
swap(lc[x],rc[v])(因为左右子树互换,相应最左最右颜色要换
IF(exist tag operation):
To intialize rc[x],lc[x],vc[x],num[x];
IF(exist left_tree)tag[ls[x][0]]=tag[x];
IF(exist right_tree)tag[ls[x][1]]=tag[x];
clear tag[x];(tag[x]=-1 becase $color \in [0,10^9]$)
(8)简单说一些其他
LCT自带log的常数,并且我自带巨大常数,用时是树剖的4倍以上
不过代码比树剖短1K左右,比较好打
不过LCT没有用到堆栈,不用担心栈溢出的问题
yy一下,比如支持连边操作,断边操作等等能够修改树的形态的操作,有没有什么好的做法?
代码:
LCT
#include <cstdio> #include <algorithm> const int N=100005; int n,m; struct LinkCutTree{ int fa[N],ls[N][2]; int rev[N],num[N],tag[N],lc[N],rc[N],vc[N]; void Down(int &x){ int &tl=ls[x][0],&tr=ls[x][1]; if(rev[x]){ if(tl)rev[tl]^=1;if(tr)rev[tr]^=1;rev[x]=0; std::swap(tl,tr);std::swap(lc[x],rc[x]); } if(tag[x]!=-1){ lc[x]=rc[x]=vc[x]=tag[x];num[x]=1; if(tl)tag[tl]=tag[x];if(tr)tag[tr]=tag[x];tag[x]=-1; } } void Up(int &x){ int &tl=ls[x][0],&tr=ls[x][1]; if(rev[tl] || tag[tl]!=-1)Down(tl); if(rev[tr] || tag[tr]!=-1)Down(tr); if(tl)lc[x]=lc[tl];else lc[x]=vc[x]; if(tr)rc[x]=rc[tr];else rc[x]=vc[x]; num[x]=num[tl]+num[tr]+1; if(tl&&rc[tl]==vc[x])--num[x]; if(tr&&lc[tr]==vc[x])--num[x]; } bool IsRoot(int x){return ls[fa[x]][0]==x || ls[fa[x]][1]==x;} void Rotate(int x){ int y=fa[x],z=fa[y],s=ls[y][1]==x; if(IsRoot(y))ls[z][ls[z][1]==y]=x;fa[x]=z; fa[ls[y][s]=ls[x][s^1]]=y; fa[ls[x][s^1]=y]=x; Up(y);Up(x); } void Pr(int x){if(IsRoot(x))Pr(fa[x]);Down(x);} void Splay(int x){ Pr(x); for(int y;IsRoot(x);Rotate(x)) if(IsRoot(y=fa[x])) if((x==ls[y][0])^(y==ls[fa[y]][0])) Rotate(x);else Rotate(y); } void Access(int x){ for(int y=0;x;x=fa[y=x]){ Splay(x);Up(fa[ls[x][1]=y]=x); } } void Markroot(int x){Access(x);Splay(x);rev[x]^=1;} void Link(int x,int y){Markroot(x);Markroot(y);fa[y]=x;} void Split(int x,int y){Markroot(x);Access(y);Splay(y);} }T; int Read(){ int ch='@',t=0; for(;ch<48 || 57<ch;ch=getchar()); for(;47<ch && ch<58;ch=getchar())t=t*10+ch-48; return t; } int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); n=Read();m=Read();T.tag[0]=-1; for(int i=1;i<=n;++i){ T.lc[i]=T.rc[i]=T.vc[i]=Read(); T.num[i]=1;T.tag[i]=-1; } for(int i=1,a,b;i<n;++i){ a=Read();b=Read();T.Link(a,b); } char op; for(int i=1,a,b,c;i<=m;++i){ scanf("\n%c",&op);a=Read();b=Read(); if(op=='C'){ c=Read();T.Split(a,b);T.tag[b]=c; }else{ T.Split(a,b);printf("%d\n",T.num[b]); } } //fclose(stdin);fclose(stdout); return 0; }