您的位置:首页 > 其它

【学习】动态树 link cut tree

2017-03-23 09:24 267 查看

介绍

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lct