LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解

转载 :扯淡(前言)
众所周知LCT可以支持关于点权的链修改,换根,LINK,CUT和查询链信息操作,但是总有那么些神犇(毒瘤)出题人会让你在支持链修改,换根,LINK和CUT操作的情况下去支持子树查询,或者维护关于边权的链修改,换根,LINK,CUT和链查询。网上似乎讲解这两种LCT写法的blog比较少或者不怎么能搜到?总之我来写一发
(LCT基础知识回顾)


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

那么我们可以定义一个点x在LCT结构中的儿子,为有虚边指向x的点或者在splay中是x的儿子的点,例如上图中,4在LCT结构中的儿子有7和2,并且由此我们可以定义出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换根,然后连一条x到y的虚边,这时我们发现不仅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)并且2在4的splay子树里,但是4的splay子树所代表的链是不包含(2,1)的
那么我们考虑这个信息的合并,如果一个点有左子树,那么他的前一条边的另一个端点一定在左子树里,所以他的链信息和就要加上左子树的链信息和以及他的前一条边的信息,右子树亦然
我们考虑链修改操作,与链信息合并类似,如果他有左儿子,那么更改他的前一条边的权值,右儿子亦然,然后对这个点打标
然后就完成了边权的维护
代码可参照UOJ#207 共价大爷游长沙
---------------------
作者:neither_nor
来源:CSDN
原文:https://blog.csdn.net/neither_nor/article/details/52979425
版权声明:本文为博主原创文章,转载请附上博文链接!

posted @ 2019-01-16 11:09  zjxxcn  阅读(793)  评论(0编辑  收藏  举报