【学习】动态树 link cut tree

介绍

LCT是动态的树链剖分,他用 Splay 维护重链的信息,并且动态维护重链。
可以支持合并分割操作,并且动态维护树链的信息。
原树中的重链对应的是 Splay 中的实边,轻链对应轻边,这样一棵树被划分成了若干个 Splay
Splay 的中序遍历是从浅到深的顺序。

基本的操作

Splay-is_root()

bool is_root(){return pre->ch[0] != this && pre->ch[1] != this;}
//判断一个Splay节点是不是当前Splay的根。

Splay-rotate(x)

void rotate(node *now){
    node *fa = now->pre, *gra = fa->pre;
    int wh = now->wh();
    //如果当前点的fa不是splay的根,那要跟新gra的孩子信息,这一句话要放在前面,后面fa的信息改变了,就判断不了了。
    if(!fa->is_root()) gra->ch[gra->ch[0] == fa ? 0 : 1] = now;
    fa->set_ch(wh, now->ch[wh^1]);
    now->set_ch(wh^1, fa), now->pre = gra;
}

Splay-splay(x)

//需要先将当前点的所有的祖先节点的标记全部下放,在考虑操作当前点。
void splay(node *now){
    int stt = 0; st[++ stt] = now;
    for(node *i = now; !i->is_root(); i = i->pre) st[++ stt] = i->pre;
    for(int i = stt; i >= 1; i --) st[i]->down(); 
    //边界条件是now只要不是根就继续转,now->pre不是根,就考虑双旋。
    for( ; !now->is_root(); rotate(now))
        if(!now->pre->is_root())
            now->wh() == now->pre->wh() ? rotate(now->pre) : rotate(now); 
}

LCT-access(x)

//把x所在的树的重链,从根连接到x。
void access(node *x){
    //最开始的一个
    for(node *i = null; x != null; i = x, x = x->pre) 
        splay(x), x->set_ch(1, i);
}

LCT-makeroot(x)

//把x变成新的根,只需要把x到原根的路径全部取反即可。
void makeroot(node *x){
    access(x), splay(x), x->rev ^= 1;
}

LCT-split(x, y)

//提取出x到y的一条链到一个splay里,并让x成为splay的根。
void split(node *x, node *y){
    makeroot(y), access(x), splay(x);
}

LCT-link(x, y)

//将x变为根,直接向y连一条虚边即可。
void link(node *x, node *y){
    makeroot(x); x->pre = y;
}

LCT-cut(x, y)

//切断x与y之间的边。
void cut(node *x, node *y){
    //让x成为y的左子树,断开连接的边即可。
    makeroot(x); access(y); splay(y);
    y->set_ch(0, null); x->pre = null;
}

题目

BZOJ 2049 [Sdoi2008]洞穴勘测

思路:

LCT模板题,维护联通块即可。

代码:2049.cpp

BZOJ 2631 tree

思路:

LCT模板题,注意两个不同标记的合并就好了。

代码:2631.cpp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值