【算法简介】
又是一个大数据结构!
简单的说,LCT是维护了一个森林,每个树都是一棵splay,由虚边连接着各个树
支持操作:
- 查询、修改链上的信息(最值,总和等)
- 随意指定原树的根(即换根)
- 动态连边、删边
- 动态维护连通性
性质:
每一个Splay维护的是一条从上到下按在原树中深度严格递增的路径,且中序遍历Splay得到的每个点的深度序列严格递增。
边分为实边和虚边,实边包含在Splay中,而虚边总是由一棵Splay指向另一个节点(指向该Splay中中序遍历最靠前的点在原树中的父亲)。
操作函数:
1.access
access即为打通根节点到指定节点的实链,使得一条中序遍历以根开始、以指定点结束的Splay出现。
实现方式:
- 转到根
- 换儿子
- 更新信息
- 当前操作点切换为轻边所指的父亲,转1
void access(int x)
{
for(int y=0;x;y=x,x=fa(x))
splay(x),rc(x)=y,pushup(x);
}
2.makeroot
makeroot旨在将指定节点转换为原树的根
void pushrev(int x)
{
swap(lc(x),rc(x));
tr[x].rev^=1;
}
void makeroot(int x)
{
access(x); splay(x);
pushrev(x);
}
3.findroot
findroot找到原树的根,一般用于判断连通性
int findroot(int x)
{
access(x); splay(x);
while(lc(x)) pushdown(x),x=lc(x);
splay(x);
return x;
}
4.split
split是把x-y的路径取出来
void split(int x,int y)
{
makeroot(x);
access(y); splay(y);
}
5.link
连接x-y的边
void link(int x,int y)
{
makeroot(x);
if(findroot(y)==x) return;//保证连边合法时不用加
fa(x)=y;
}
6.cut
断开x-y的边
void cut(int x,int y)
{
makeroot(x);
if(findroot(y)!=x || tr[x].siz>2) return;//保证断边合法时不用加
fa(y)=rs(x)=0;
pushup(x);
}
【习题】
1.P2387 [NOI2014] 魔法森林
这个是经典的LCT操作,不断加边,直到出现环,断一条环上最劣边继续维护即可
2.P4219 [BJOI2014]大融合
典型的LCT维护子树信息,注意下access和link操作时候对虚儿子信息的影响