首页 > 其他 > 详细

[模板] 动态树/LCT

时间:2019-01-15 11:28:01      阅读:202      评论:0      收藏:0      [点我收藏+]

简介

LCT是一种数据结构, 可以维护树的动态加边, 删边, 维护链上信息(满足结合律), 单次操作时间复杂度 \(O(\log n)\).(不会证)

思想类似树链剖分, 因为splay可以换根, 用splay维护重链, splay的中序遍历即为链按深度从小到大遍历的结果.

注意区分splay和整棵树的区别, splay根和树根的区别.

\(Access(p)\) 操作指的是将p与根放在同一棵splay中.

\(MakeRoot(p)\) 操作指的是将p变为它所在树(而不是splay)的根. 由于维护的是链上信息, 这不会对答案产生影响.

\(FindRoot(p)\) 操作指的是求p所在树(而不是splay)的根.

\(Link(x,y)\) 操作指的是如果p与q不在同一棵树中, 那么连边 \((x,y)\).

\(Cut(x,y)\) 操作指的是如果p与q有边相连, 那么连边 \((x,y)\).
其中, ‘p与q有边相连‘ 等价于同时满足:
- p,q在同一棵树中.
- p,q深度相差1.(splay中p,q中序遍历时相邻)

\(Split(x,y)\) 操作指的是取出 \((x,y)\) 这个链, 并放在一棵splay中.

具体实现见代码.

Code

const int nsz=3e5+50;
int n,val[nsz];
struct tlct{
    struct tnd{int ch[2],fa,sum,rv;}tree[nsz];
#define ls(p) tree[p].ch[0]
#define rs(p) tree[p].ch[1]
#define fa(p) tree[p].fa
#define dir(p) (rs(fa(p))==p)
    bool isrt(int p){return ls(fa(p))!=p&&rs(fa(p))!=p;}//splay rt
    void rev(int p){swap(ls(p),rs(p));tree[p].rv^=1;}
    void pu(int p){
        tree[p].sum=tree[ls(p)].sum^val[p]^tree[rs(p)].sum;
    }
    void pd(int p){
        if(tree[p].rv==0)return;
        if(ls(p))rev(ls(p));
        if(rs(p))rev(rs(p));
        tree[p].rv=0;
    }
    void pdt(int p){//push down whole splay
        if(!isrt(p))pdt(fa(p));
        pd(p);
    }
    void rotate(int p){//fa(p) should exist
        int x=fa(p),y=fa(x),dir1=dir(p),dir2=dir(x),z=tree[p].ch[dir1^1];
        if(!isrt(x))tree[y].ch[dir2]=p; fa(p)=y;
        tree[p].ch[dir1^1]=x;           fa(x)=p;
        tree[x].ch[dir1]=z;             if(z)fa(z)=x;
        pu(x);
        pu(p);
    }

    void splay(int p){
        pdt(p);
        while(!isrt(p)){
            if(!isrt(fa(p)))rotate(dir(p)==dir(fa(p))?fa(p):p);
            rotate(p);
        }
    }

    void access(int p){
        for(int y=0;p;y=p,p=fa(p)){
            splay(p),rs(p)=y;
            pu(p);
        }
    }
    void makert(int p){//p -> tree rt & splay rt
        access(p),splay(p);
        rev(p);
    }
    int findrt(int p){//find tree rt; p -> splay rt
        access(p),splay(p);
        while(ls(p))pd(p),p=ls(p);
        return p;
    }
    bool iscon(int x,int y){return findrt(x)==findrt(y);}
    void link(int x,int y){
        makert(x);
        if(findrt(y)!=x)fa(x)=y;
    }
    void cut(int x,int y){
        makert(x);
        if(findrt(y)==x&&fa(x)==y&&ls(x)==0)
            fa(x)=ls(y)=0,pu(y);
    }
    void split(int x,int y){//y -> splay rt
        makert(x);
        access(y);
        splay(y);
    }
    void pr(){
        rep(i,1,n)printf("nd=%d fa=%d ls=%d rs=%d sum=%d rv=%d\n",i,fa(i),ls(i),rs(i),tree[i].sum,tree[i].rv);
    }
}lct;

//init
rep(i,1,n)tree[i].sum=val[i];

//query a chain
    lct.split(b,c);
    ans=lct.tree[c].sum;

//modify one point
    lct.makert(b);
    val[b]=c;
    lct.pu(b);

[模板] 动态树/LCT

原文:https://www.cnblogs.com/ubospica/p/10270646.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!