LCT维护操作。。

转自:blog.csdn.net/wu_tongtong/article/details/78654635
http://blog.csdn.net/neither_nor/article/details/52979425

LCT基础知识回顾)
为了方便说话先说一下下面可能出现的名词的意思(。其实大家可以先跳过这一段,如果后面没看懂我在写什么再回来看这里)
我们要用LCT维护一棵树,那么这棵树会有一个原树结构,以及一个当前在LCT里的结构,我们知道我们用LCT维护了一个原树的链剖分,凡是被剖分到同一条链里的点用一个splay以深度为关键字维护,而不同的链之间用虚边相连,虚边为只有儿子指向爹,爹不指向儿子

那么我们可以定义一个点x在LCT结构中的儿子,为有虚边指向x的点或者在splay中是x的儿子的点,例如上图中,4在LCT结构中的儿子有72,并且由此我们可以定义出LCT结构里的子树,上图中4的子树包含4,7,2,6,8,5
由于虚实边的存在,我们可以把儿子分为实儿子和虚儿子,实儿子为splay中的儿子,虚儿子为有虚边指向他的儿子,我们还可以把子树划分为实子树、虚子树和自己三部分,实儿子的子树为实子树,虚儿子的子树为虚子树(实儿子的虚子树也算实子树的一部分)
例如上图中,4的实儿子有2,虚儿子有7,实子树包含2,5,6,8,虚子树包含7
子树信息
我们先来考虑维护子树的信息和
对于一个点x,如果我们对x进行access操作,那么他的虚子树内将包含且仅包含他原树中子树内除了他自己以外的所有点,这时如果我们维护了他的虚子树信息和,我们把这个信息与他自己的信息合并,我们就得到了他在原树中的子树信息
在下面的讨论中,我们发现我们可以同时维护一个点的虚子树信息和LCT子树信息来达到维护虚子树信息的目的
考虑一个点的虚子树信息会在什么情况下发生改变,一个点的虚子树信息改变,当且仅当进行link或者access操作时。
在进行access操作时,我们会有更换一个点的x右儿子的操作,这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,把x的新的右儿子的LCT子树信息从x的虚子树信息中减去
在进行link操作时,我们会先把点x换根,然后连一条xy的虚边,这时我们发现不仅y的虚子树信息需要加入x的LCT子树信息,y的所有祖先的LCT子树信息也需要更改,而这样我们就没法维护了,所以在进行link操作的时候我们需要把y也换根(其实access再splay就行了,不用换成根),这样就只会对y的虚子树信息和LCT子树信息产生影响
我们还需要维护一个x的LCT子树的信息和,x的LCT子树的信息和就等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己,在splay的update函数中就可以直接维护
这样我们就完成了对子树信息的维护
换根操作、cut操作和链修改操作并不影响我们上边的讨论,所以也是兹磁的
代码可参照BZOJ4530 [Bjoi2014]
边权信息
这个边权信息的维护方法是从vfk的博客里学的,不过他那篇文章本来是讲动态仙人掌的-_-LCT并不是重点
对于每个点,我们定义他的“前一条边”和“后一条边”,前一条边指的即是他在原树中与父亲之间的边(可能不存在),而后一条边指的是在当前的链剖分下,与他在同一条剖分链上的儿子与他之间的边(可能不存在)
例如上图中,1的前一条边与4的后一条边都是不存在的,而2的前一条边就是(1,2),后一条边是(2,4),5的前一条边就是(2,5)
我们考虑对于每个点,维护他的前一条边和后一条边是哪条,注意是维护是哪条边,而不是直接维护边权
考虑在什么情况下前一条边和后一条边会发生变化,首先在进行翻转操作时,我们显然除了交换左右儿子还要交换前一条边和后一条边,在link操作时,我们要把x的前一条边设成(x,y),在cut时,我们要把cut掉的两个点其中一个的前一条边设成没有,另一个的后一条边设成没有
另外在access操作时,我们有更换x的右儿子的操作,即改变了当前的链剖分,所以x的后一条边理应变成他新的右儿子所在的splay里最左边的点的前一条边,而为了找到这一条边,我们还需要维护每个splay的第一条边和最后一条边,即最左边的点的前一条边和最右边的点的后一条边,为什么要维护最后一条边呢,因为在翻转的时候我们要交换这两个值
这样的话,我们对每个点维护他的splay子树所代表的链的边权信息和,注意一个splay所代表的链所包含的边只有那些两个端点都在这个splay里的边,比如上图中2的前一条边是(2,1)并且24的splay子树里,但是4的splay子树所代表的链是不包含(2,1)的
那么我们考虑这个信息的合并,如果一个点有左子树,那么他的前一条边的另一个端点一定在左子树里,所以他的链信息和就要加上左子树的链信息和以及他的前一条边的信息,右子树亦然
我们考虑链修改操作,与链信息合并类似,如果他有左儿子,那么更改他的前一条边的权值,右儿子亦然,然后对这个点打标
然后就完成了边权的维护
代码可参照UOJ#207 共价大爷游长沙 
首先我们要明确一棵LCT到底是怎么维护信息的:

这里写图片描述

我们可以发现,我们在expose一个结点之后(如图,假如我们expose的是4)
该点的所有虚边所连的点集就是该点的在原树上的子树(除该点本身的信息)

所以我们是可以利用这一个性质的
子树信息:

对于一个点x,如果我们对x进行expose操作
那么ta的虚子树内将包含且仅包含 ta原树中子树内除了ta自己以外的所有点

如果我们维护了ta的虚子树信息和,我们把这个信息与ta自己的信息合并,我们就得到了ta在原树中的子树信息
在下面的讨论中,我们发现我们可以同时维护一个点的虚子树信息和LCT子树信息来达到维护虚子树信息的目的

我们需要维护一个x的LCT子树的信息和
x的LCT子树的信息和就等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己,

在splay的update函数中就可以直接维护

考虑一个点的虚子树信息会在什么情况下发生改变:
一个点的虚子树信息改变,当且仅当进行link或者expose操作时
在进行expose操作时,

我们会有更换一个点x的右儿子的操作,
这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,
把x的新的右儿子的LCT子树信息从x的虚子树信息中减去
(一定细细体会这句话蕴含的真理)
在进行link操作时,

我们会先把点x换到根上,然后连一条xy的虚边,
这时我们发现不仅y的虚子树信息需要加入x的LCT子树信息,y的所有祖先的LCT子树信息也需要更改,
所以在进行link操作的时候我们需要makeroot(x)再makeroot(y),
我们把x的爸爸设成y,这样只要把x的LCT子树信息统计入y得虚子树信息中即可
(不要忘了update(y))
换根操作、cut操作和链修改操作并不影响我们上边的讨论

例题:bzoj4530:题解
边权信息

对于每个点,我们定义他的“前一条边”和“后一条边”,
前一条边指的即是ta在原树中与父亲之间的边(可能不存在),而后一条边指的是在当前的链剖分下,与ta在同一条剖分链上的儿子与他之间的边(可能不存在)
例如上图中,1的前一条边与4的后一条边都是不存在的,而2的前一条边就是(1,2),后一条边是(2,4),5的前一条边就是(2,5)

对于每个点,维护ta的前一条边和后一条边是哪条,注意是维护是哪条边,而不是直接维护边权

考虑在什么情况下前一条边和后一条边会发生变化:

    在翻转操作时,我们显然除了交换左右儿子还要交换前一条边和后一条边
    在link操作时,我们要把x的前一条边设成(x,y)
    在cut操作时,我们要把cut掉的两个点其中一个的前一条边设成“不存在”,另一个的后一条边设成“不存在”
    在access操作时,我们有更换x的右儿子的操作,即改变了当前的链剖分,
    所以x的后一条边理应变成他新的右儿子所在的splay里最左边的点的前一条边,
    而为了找到这一条边,我们还需要维护每个splay的第一条边和最后一条边,
    即最左边的点的前一条边和最右边的点的后一条边,
    为什么要维护最后一条边呢,因为在翻转的时候我们要交换这两个值

这样的话,我们对每个点维护他的splay子树所代表的链的边权信息和,
注意一个splay所代表的链所包含的边只有那些两个端点都在这个splay里的边,
比如上图中2的前一条边是(2,1)并且24的splay子树里,但是4的splay子树所代表的链是不包含(2,1)的

考虑信息的合并:
如果一个点有左子树,那么他的前一条边的另一个端点一定在左子树里,
所以他的链信息和就要加上左子树的链信息和以及他的前一条边的信息,右子树亦然

我们考虑链修改操作:
与链信息合并类似,如果他有左儿子,那么更改他的前一条边的权值,右儿子亦然,然后对这个点打标

这样就完成了边权的维护
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值