lct学习笔记

lct不能够实现“对某个点的子树进行的某些操作”(但可以实现类似求子树大小的简单操作),然而对于大部分动态树问题来说还是够用了。
主要的四个操作。
1,Access(x),把原树上x到根路径上的所有点放到同一颗splay里面
2,Makeroot(x),让x成为所在树的根
3,Cut(x,y),切断相邻的节点x,y的边
4,Link(x,y),让x,y连一条树边,成为属于原图的同一棵树。

基本定义
splay(x,y)表示x旋转到为y的儿子
fa[x]为splay中的x的父亲。
其中每个splay的根root都记录了一个tfa[root]表示在这棵splay中深度最小的点在树中的父亲。

Access(x)
1,splay(x,0),splay上,断开右子树,右子树的顶端y记录tfa[y]=x
2,令last=x,x=tfa[x],执行操作1,并让last所在子树成为x的右子树。(splay上)
3,重复操作2直至tfa[x]=0。

Makeroot(x)
1,Acccess(x)
2,splay(x,0)
3,给x所在的splay打翻转标记
access(x)之后,原树其他点到这个重链上的所有点都是轻边了,无论是这个重链的谁作为根,轻边的信息都不会变质。而x为重链的最深点,把它作为根,那么深度顺序就反了过来,所以翻转。

Cut(x,y)
1,Makeroot(x)
2,Access(y)
3,splay(y,0)
4,在splay上,把y的左子树断掉。
makeroot(x)后x肯定是y的父亲了。为了其他点的信息不被破坏,我们断掉y所在的重链,让x,y于同一重链,把y的左子树断掉,即x和y断掉了,此时tfa[y]肯定是0,因为x是根。

Link(x,y)
1,Makeroot(x)
2,splay(x,0)
3,tfa[x]=y
makeroot(x)后再把x旋到根,tfa[x]=0,直接连向y即可。

模板

bool pd(int x){return(tree[fa[x]][0]==x)?0:1;}
void re(int x){
    if (!x) return;
    bz[x]^=1,swap(tree[x][0],tree[x][1]);
}
void update(int x){
    int l=tree[x][0],r=tree[x][1];
    num[x]=max(max(num[l],num[r]),x);
}
void clear(int x){
    int l=tree[x][0],r=tree[x][1];
    if (bz[x]) re(l),re(r);
    bz[x]=0;
}
void rotate(int x){
    int y=fa[x],z=pd(x),z1=pd(y);
    if (tree[y][z]=tree[x][z^1]) fa[tree[y][z]]=y;
    if (fa[x]=fa[y]) tree[fa[x]][z1]=x;
    if (tfa[y]) tfa[x]=tfa[y],tfa[y]=0;
    fa[y]=x,tree[x][z^1]=y,update(y);
}
void chu(int x,int y){
    q[0]=0;
    for(;x!=y;x=fa[x]) q[++q[0]]=x;
    for(;q[0];q[0]--) clear(q[q[0]]);
}
void splay(int x,int y){
    chu(x,y);
    while (fa[x]!=y){
        int f=fa[x];
        if (fa[f]!=y){
            if (pd(x)==pd(f)) rotate(f);else rotate(x);
        }rotate(x);
    }update(x);
}
void access(int x){
    int last=0,y;
    for(;x;last=x,x=tfa[x]){
        splay(x,0);
        y=tree[x][1];
        if (y) tree[x][1]=0,fa[y]=0,tfa[y]=x;
        if (last)tree[x][1]=last,fa[last]=x,tfa[last]=0;
        update(x);
    }
}
void makeroot(int x){
    access(x);
    splay(x,0);
    re(x);
}
void link(int x,int y){
    makeroot(x);
    splay(x,0);
    tfa[x]=y;
}
void cut(int x,int y){
    makeroot(x);
    access(y);
    splay(y,0);
    tree[y][0]=0,fa[x]=0,update(y);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值