您的位置:首页 > 其它

Link-Cut Tree

2017-05-17 19:28 393 查看
ps:推荐论文《QTREE解法的一些研究》by杨哲。

作用

高效解决动态树问题。

思想

Link-Cut Tree(简称LCT)将树的边分为Prefered Edge和普通边,将点分为Prefered Child和普通点,Prefered Edge和Prefered Child是不断变化的,且刚开始只有普通边和普通点。LCT的核心操作Access(x):访问x。

假设最后访问了lst节点,对于节点x,如果lst在x的儿子son的子树中,则son变成x的Prefered Child(原先的Prefered Child变为普通点),连接x和son的边变成Prefered Edge(原先的Prefered Edge变为普通边,由此可见x至多只有一个Prefered Child)。特殊的是,lst没有Prefered Child。那么显然访问了lst之后,lst到ro(ro表示lst所在树的根)之间的边都变成Prefered Edge了。

对于一条由Prefered Edge连接而成的链,我们用数据结构(通常用Splay,因为Splay可以方便的分裂和合并)来维护,将链自顶向下看做一个序列(dep越小越靠前)用Splay储存,且这条链的Splay的根节点储存了一个Path Father,表示这条链顶端节点的father。要注意,这个关系是单向的,也就是说这条链的Splay的根节点的father是Path Father,但Path Father所在Splay和这条链的Splay是不连通的。

假设我们已经实现了Access,那么如何实现Link(x,y)(把y连接到x上)和Cut(x,y)(把y从x上断开)呢?首先我们需要实现一个make_ro(p),作用是把p变成p所在树(注意,不是p所在Splay!)的根。代码如下:

void make_ro(int p) {Access(p);Splay(p);Add_flip(p);}


非常简短,但是好像很费解,我们来看图:



先访问p,这样p到ro之间的边就都变成Prefered Edge了(也就是说p到ro之间的点都在同一个Splay中了),然后把p伸展到p所在Splay的根。由于p是最深的节点,所以其他点均在p的左边,但是p成为了根节点,这条链就被翻转了,加翻转标记。完成这三个操作之后,p就成为了新根。

有了make_ro操作,Link和Cut就很简单了:

void Link(int x,int y) {Access(y);make_ro(y);father[y]=x;}


先把y变成根,然后把father[y]给x就行了(不要把son[x][0/1]给y,因为这是单向连接)。

void Cut(int x,int y)
{
make_ro(y);Access(x);Splay(x);
father[y]=son[x][0]=0;Pushup(x);
}


先把y变成根,然后访问x,访问之后x所在链中就只有x和y两个节点了,伸展x,则y必定是x的左二子。断开连接,更新x。

然而Access还没讲,其实非常暴力,假设目前处理到p,上次处理了lst。那么先断开p与原先Prefered Child之间的连接,然后连接p和lst,更新p。重复这个过程直到p为空。

void Access(int p)
{
int lst=0;
while (p)
{
Splay(p);son[p][1]=lst;Pushup(p);
//先Splay(p),这样son[p][1]就是原先p的Prefered Child的子树了
//将son[p][1]给成lst,更新p
//不用修正father[son[p][1]],因为p成为了father[son[p][1]]的Path Father
lst=p;p=father[p]; //继续处理
}
}


这样不会超时吗?之后再讲。

除了Link和Cut,我们还可以实现以下功能:

1.取出x->y的路径

make_ro(x),Access(y),此时x->y的路径被存在同一棵Splay中。

2.求x和y的LCA

Access(x),Access(y),Splay(x),则LCA=x的Path Father。

特殊:当x没有Path Father时,LCA=x(因为y跨越了x到ro,所以x没有Path Father)。

效率

Splay的总效率为O((n+Q)∗log2(n)),但是Access的总效率呢?

Access的效率取决于Prefered Child改变的次数,而Prefered Child改变的次数取决于Prefered Edge改变的次数。Prefered Edge和普通边不禁让我们想到了树链剖分-轻重链剖分中的重边和轻边。根据轻重链剖分的定义,我们会发现每次Access,至多有log2(n)条普通边变成了轻的Prefered Edge,也就是说普通边变成轻的Prefered Edge的总次数为(n+Q)∗log2(n)。但是有多少普通边变成了重的Prefered Edge呢?我们转化一下,普通边变成重的Prefered Edge的次数=重的Prefered Edge变成普通边的次数+n(可能最后全是重的Prefered Edge),而重的Prefered Edge变成普通边必定意味着一条普通边变成了轻的Prefered Edge,所以普通边变成重的Prefered Edge的次数=(n+Q)∗log2(n)+n。

综上所述Access的总效率为O((n+Q)∗log2(n)),也就是说LCT的总效率为O((n+Q)∗log2(n))。

ps:然而Splay常数巨大,所以LCT常数巨大……

模板题

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