[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;
}

 

posted @ 2017-04-18 01:08  hjj1871984569  阅读(176)  评论(0编辑  收藏  举报