学习笔记——LCT

LCT长于维护链上的信息,支持树链上各种黑科技操作,但对于维护子树信息,则没有树剖来得更方便。

 

LCT主要维护点权,如果要维护边权,可以为边新开一个点接在两个点上。通过维护边权可以实现一些贪心的动态维护最小生成树——即加进一条边形成一个环,删掉环中最大的边。

类似的题目有:严格次小生成树,最小差值生成树,NOI2014魔法森林

 

对于维护字树信息,和DDP类似,再来一个数组记录虚儿子的总答案,然后在$access$和$link$时更新即可,参考大裸题:大融合

 

对于维护点双等连通性问题,可以再来一个并查集,因为缩点以后没法加回来,所以对于删边操作,我们考虑离线,把删边改为加边,然后LCT维护,调用直接并查集序号即可

 

代码:

在实现方面,要注意splay之前要$pushall$,$findroot$之后要$splay(x)$,时时刻刻记得$pushup$,在$rotate$的时候要注意特判一个$y$是否为根,access的时候要先splay再赋值右儿子

#define ls ch[x][0]
#define rs ch[x][1]
namespace LCT{
    int ch[N+M][2],fa[N+M],rev[N+M],mx[N+M];
    void init(int x){rev[x]=0,ch[x][0]=ch[x][1]=0;fa[x]=0;mx[x]=x;}
    void DEL(int x){ch[x][0]=ch[x][1]=fa[x]=rev[x]=mx[x]=0;val[x]=0;}
    int getdir(int x){return (ch[fa[x]][1]==x);}//0:left 1:right
    int isRoot(int x){DEL(0); return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    void pushup(int x){
        mx[x]=x;
        if(ls) if(val[mx[x]]<val[mx[ls]]) mx[x]=mx[ls];
        if(rs) if(val[mx[x]]<val[mx[rs]]) mx[x]=mx[rs];
    }
    void pushdown(int x){
        if(rev[x])
        {
            if(ls) swap(ch[ls][0],ch[ls][1]), rev[ls]^=1;
            if(rs) swap(ch[rs][0],ch[rs][1]), rev[rs]^=1;
            rev[x]=0;
        }
    }
    void pushall(int x){if(!isRoot(x)) pushall(fa[x]); pushdown(x);}
    void rotate(int x){
        int y=fa[x],z=fa[y],dirx=getdir(x),diry=getdir(y);
        if(!isRoot(y)) ch[z][diry]=x;
        ch[y][dirx]=ch[x][dirx^1]; if(ch[x][dirx^1]) fa[ch[x][dirx^1]]=y;
        ch[x][dirx^1]=y; fa[y]=x; fa[x]=z;
        pushup(y); pushup(x);
    }
    void splay(int x){
        pushall(x);
        int F=fa[x];
        while(!isRoot(x))
        {
            if(!isRoot(F))
            {
                if(getdir(F)==getdir(x)) rotate(F);
                else rotate(x);
            }
            rotate(x);
            F=fa[x];
        }
    }
    void access(int x){
        for(int now=0;x!=0;now=x,x=fa[x])
        { 
            splay(x); 
            ch[x][1]=now; pushup(x);
        }
    }
    void makeroot(int x){
        access(x); 
        splay(x);
        rev[x]^=1; swap(ls,rs);
    }
    int findroot(int x){
        access(x); splay(x);
        while(ch[x][0]) 
        {
            pushdown(x);
            x=ch[x][0];
        }
        splay(x);
        return x;
    }
    void link(int x,int y){
        makeroot(x);
        fa[x]=y;
    }
    void cut(int x,int y){
        makeroot(x); 
        access(y); splay(y);
        fa[x]=0; ch[y][0]=0;
        pushup(y);
    }
    void split(int x,int y){
        makeroot(x);
        access(y); splay(y);
        pushup(y);
    }//y is the root   
}
View Code

 

posted @ 2020-06-15 22:40  'Clovers'  阅读(137)  评论(0编辑  收藏  举报