Link-Cut-Tree
wcz¹
December31,2017
¹Contactme:
aiyoupass@outlook.com
Contents
1DynamicTreeProblems[2]
2
2Link-Cut-Trees[3]
3
2.1Build
..................................3
2.2Access
.................................6
2.3Isroot
..................................6
2.4Findroot
................................6
2.5Beroot
.................................6
2.6Split
...................................6
2.7Merge
..................................7
2.8Code
..................................7
3Pathoperation*[1]
8
3.1Example1
...............................9
4Others
9
4.1Connect
................................9
1
![](https://i-blog.csdnimg.cn/blog_migrate/3e1779f6d679f7f68199e99fc597eb84.png)
1DynamicTreeProblems[
2]
动态树问题
,即要求我们维护一个由若干棵子结点无序的有根树组成的
森林
.要求这个数据结构支持对树的分割
,合并
,对某个点到它的根的路径的
某些操作
,以及对某个点的子树进行的某些操作
.
维护一个包含
N个点的森林
,并且支持形态和权值信息的操作
.
(1).
形态信息
(a).link(u,v)–
添加边(u,v).
(b).cut(u,v)–
删除边(u,v).
(c).find(u)–
找到u
所在的树.
(2).
权值信息
(a).
路径操作:
对一条简单路径上的所有对象进行操作.
(b).
树操作:
对一棵树内的所有对象进行操作.
现有数据结构
,
•EulerTourTrees
¹
•ST-Trees
²
•Top-Trees
³
这几种数据结构都存在一定的局限性
,因此动态树问题并没有被完全解
决
.
在信息学奥赛中
,我们常常会遇到动态树的简化问题
.我们涉及的操作只
有对树形态的操作和对于路径的操作
.因此就有一种解决动态树问题的数据
结构
Link
−cut
−Trees
⁴
¹
不支持路径操作
²
不支持树权操作
³
常数过大
⁴
由Sleator
和Tarjan
发明
2
![](https://i-blog.csdnimg.cn/blog_migrate/5c5d30186e0045010f5c92cf8d83e73a.png)
2Link-Cut-Trees[
3]
Link-Cut-Trees,
简称LCT,
它对上述操作的均摊时间不超过O(log
n).
它所操作的对象是森树
,能实现对于树的合并与分离
.
a
b
c
d
e
f
g
h
i
FormerTree
这是一颗已经构建好的树
(森林
),我们用
Link-Cut-Trees来维护它.
2.1Build
对于一个节点进行访问的操作称为
Access;
称我们要表示的这棵树为
FormerTree;
PreferredChild,
如果对于节点u所在的子树中,
节点v为最后访问过的
点
,则称节点
v为节点
u的
PreferredChild;
PreferredEdge,
每个点到PreferredChild
的边称为PreferredEdge.
preferredPath,
由preferredEdge
构成的不可再延伸的路径称为Preferred
Path.
3
![](https://i-blog.csdnimg.cn/blog_migrate/71a3175f780a21de53584737dff84b2f.png)
a
b
c
d
e
f
g
h
i
此时
a为最后一次
Access的点
假若上图就是对
FormerTree标记了
PreferredEdge的图
.
AuxiliaryTree,
在每一条PreferredPath
中,
以路径上点的深度为关键字,
用
SplayTree
来维护它,
就是AuxiliaryTree;
在
AuxiliaryTree中
,每个点的左子树中的点
,都在
PreferrdPath中这个点的
上方
;右子树中的点都在
PrefreedPath中这个点的下方
.
Pathparents,
用Pathparents
来表示其AuxiliaryTree
对应的PreferrdPath
中
最高的节点
;
因为
FormerTree可以用若干条PrefreedEdge来表示,用每个AuxiliaryTree
表示一条
preferrdEdge,那么我们最终所构建的就是一颗用
ParentsEdge将
所有
AuxiliaryTree连接起来的树.
因为
AuxiliaryTree可以维护
FormerTree的信息,因此在实际操作中,只需要
维护
AuxiliaryTree.
4
![](https://i-blog.csdnimg.cn/blog_migrate/179ec5725631756bfc3eeb2471597c60.png)
对三条
PreferrdEdge建立
AuxiliaryTree
b
a
d
g
i
e
c
h
f
将所有的
AuxiliaryTree用PathParent连成一棵树
b
a
d
g
e
c
h
i
f
5
2.2Access
Access
操作是Link-CutTrees的所有操作的基础.假设调用了Access(v),
那么从点
v到根结点的路径就成为一条新的
PreferredPath.如果路径上经
过的某个结点
u并不是
parent(u)的
PreferredChild,那么由于
parent(u)的
PreferredChild
会变为u,
原本包含parent(u)
的PreferredPath
将不再包含结
点
parent(u)及其之上的部分
.
在对节点
v进行一次
Access操作后
,那么它的
PreferredChild应当消失
.
先将点
v旋转到它所属的
AuxiliaryTree的根,如果v在v所属的Auxiliary
Tree
中有右儿子(
也就是v
原来的PreferredChild),
那么应该将v
在Auxiliary
Tree
中的右子树(
对应着v
的PreferredChild
之下的PreferredPath)
从Auxil-
iaryTree
中分离,
并设置这个新的AuxiliaryTree
的PathParent
为v.
然后
,如果点
v所属的
PreferredPath并不包含根结点
,设它的
PathParent
为
u,那么需要将
u旋转到
u所属的
AuxiliaryTree的根,并用点v所属的
AuxiliaryTree
替换到点u
所属的AuxiliaryTree
中点u
的右子树,
再将原来
点
u所属的
AuxiliaryTree中点u的右子树的PathParent设置为u.
如此操作
,直到到达包含根结点的
PreferredPath.
这是一个递归操作的过程
.最终目的还是完成对
preferrdEdge的修改
.
2.3Isroot
在
AuxiliaryTree中,如果一个点是root,那么他的Parent为NULL.
2.4Findroot
寻找点
v所在
AuxiliaryTree的根节点,先将v旋转到根,然后寻找其
AuxiliaryTree
中最左边的点.
2.5Beroot
注意将节点
v进行
Access操作之后
v只是变成了
AuxiliaryTree的root,
但在
FormerTree中仍然不是
root,因为
v还有左子树
.所以
Beroot操作的
意义在于将节点
v变成
FormerTree中的
root.
首先进行
Access(v)和Splay(v)操作,然后将v到root路径上点的深度反
转
,我们面对翻转的处理方法是先打标记然后在维护
Splay时处理
.
2.6Split
先访问
v,然后把v旋转到AuxiliaryTree的根,然后再断开v在它的所属
AuxiliaryTree
中与它的左子树的连接,
并设置.
6
![](https://i-blog.csdnimg.cn/blog_migrate/5bf888c8277daeb045f4bfbc8200d6fc.png)
2.7Merge
先访问
v,然后修改
v所属的
AuxiliaryTree的PathParent为w,然后再次
访问
v.
2.8Code
1
boolisroot(intx){
2
returnc[fa[x]][0]!=x&&c[fa[x]][1]!=x;
3
}
4
5
voidberoot(intx){
6
Access(x);
7
Splay(x);
8
rev[x]^=1;
9
}
10
11
voidpushdown(intk){
12
intl=c[k][0],r=c[k][1];
13
if(rev[k]){
14
rev[k]^=1;rev[l]^=1;rev[r]^=1;
15
swap(c[k][0],c[k][1]);
16
}
17
}
18
19
voidrotate(intx){
20
inty=fa[x],z=fa[y],l,r;
21
if(c[y][0]==x)l=0;
22
elsel=1;r=l^1;
23
if(!isroot(y))
24
if(c[z][0]==y)c[z][0]=x;
25
elsec[z][1]=x;
26
fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
27
c[y][l]=c[x][r];c[x][r]=y;
28
}
29
30
voidsplay(intx){
31
top=0;q[++top]=x;
32
for(inti=x;!isroot(i);i=fa[i])
33
q[++top]=fa[i];
7
![](https://i-blog.csdnimg.cn/blog_migrate/50b56db682230c8b846d06e9fec12e70.png)
34
for(inti=top;i;i−−)pushdown(st[i]);
35
while(!isroot(x)){
36
inty=fa[x],z=fa[y];
37
if(!isroot(y)){
38
if(c[y][0]==x^c[z][0]==y)
39
rotate(x);
40
elserotate(y);
41
}
42
rotate(x);
43
}
44
}
45
voidaccess(intx){
46
for(intt=0;x;t=x,x=fa[x])
47
splay(x),c[x][1]=t;
48
}
49
50
intfind(intx){
51
access(x);splay(x);
52
while(c[x][0])
53
x=c[x][0];
54
returnx;
55
}
56
voidmerge(intx,inty){
57
beroot(x);access(y);splay(y);
58
if(c[y][0]==x)
59
c[y][0]=fa[x]=0;
60
}
61
voidsplit(intx,inty){
62
beroot(x);fa[x]=y;
63
}
3Pathoperation*[
1]
针对的是对于路径的修改和查询
.对于节点
u和
v之间路径的操作
,我们
首先
Beroot(u),然后
Access(v),Splay(v).然后发现u,v之间的路径在Auxiliary
Tree
上都位于v
的左子树.
然后就进行各种维护就可以了.
8
3.1Example1
Bzoj2002
弹飞绵羊
需要维护树的分离与合并
.
如何建模
?我们考虑用
LCT,
我们注意到如果在
u位置能到达
v位置那么可以连一条边
(u,v),设
T为
空点即到达此点时已经跳出
,则查询从
u几次跳出我们可以查询在
Auxiliary
Tree
中u,t
之间路径的长度即为答案.
那么根据我们之前所提到的如何维护
路径
,我们只需要
Beroot(t),然后
Access(u),Splay(u)答案即为
size(t->le).
对于另一种操作即改变一个点所到达的点的位置
,我们只需要切开原来
的边并且重新连一条边即可
.
4Others
4.1Connect
对于树上路径信息的维护与修改
,一般会用树链剖分来做
.树链剖分是
将树划分成若干条路径并用线段树等数据结构来维护
,我们可以看到树链
剖分与
Link-Cut-Tree的联系与不同,都是将树转化成若干条链的方式,对
于树链剖分
,它只能维护静态的树的信息
,却不能对树的形态进行改变
;而
Link-Cut-Tree
能动态的改变树的形态,
也能维护树的路径信息.
例如,
给出一
棵树
,进行以下操作
.
•
求u
子树和;
•
将u
子树加上一个数;
•
求u,v
之间路径和;
•
将u,v
之间每条边加上一个数;
像这种对树上路径进行查询修改的话我们可以用树链剖分做
.
再例如
,给出一棵树
,进行以下操作
.
•
改变u,v
边权.
•
查询u,v
路径最大值.
解法一
Lint-Cut-Tree
无疑问
,这道题可以用
LCT做
,这两种操作都是
LCT所支持的基础操
作
,但是毫无疑问
,因为这道题目没有涉及到更改树形态信息
.而
LCT依据
AuxiliaryTree
实现,
不得不考虑Splay
巨大的常数.
9
解法二 树链剖分
直接用线段树来维护路径最大值
.
其他解法
[3]
References
[1]PoPoQQQ.Link-cut-tree.
[2]DanielD.SleatorandRobertEndreTarjan.Adatastructurefordynamictrees.
pages114--122,1981.
[3]YangZhe.Someresearchonqtreesolution.
10
![](https://i-blog.csdnimg.cn/blog_migrate/37780a5dfedd6169d52bed44cd322ebe.png)