[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; }?
轉載于:https://www.cnblogs.com/hjj1871984569/p/6725847.html
總結
以上是生活随笔為你收集整理的[SDOI2011]染色的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 北京现代百公里油耗显示反应迟钝怎么回事北
- 下一篇: 72v转12v20a可以接几个12的汽车