LCT 学习笔记

Part 1 基础操作

首先,最基础的 LCT 操作可以看 Oiwiki。我讲的肯定没有这上面好。

模板题

几个注意点:

  • 每次更改儿子之后需要 pushup。更改父亲,在维护子树信息时也需要进行修改。

  • findroot 是垃圾函数,大家不要去写。真的要写,每次搜索完必须要 splay 上来才能保证复杂度。

  • 对于权值标记,以及一些复杂的维护信息,需要考虑交换标记产生的影响。

  • 不要将 link 和 cut 函数在每道具体的题目中根据当前题意写不同的,保留最原始的 link 和 cut,这才会让你的代码不那么阴间。

  • 对于 splay 所有 向下走 的操作,主要是平衡树上二分的过程,在这之后,一定要将找到的那个位置 splay 上来,才能保证复杂度。


Part 2 套路题练习

好了,你已经学会 LCT 了,接下来做一点 基础套路题 来巩固吧!

[SDOI2008]洞穴勘测 (动态维护连通性&只有加边)

[TJOI2015]旅游(动态维护权值标记&较复杂的信息合并)

[NOI2014] 魔法森林(经典 LCT 与贪心的结合&动态维护边信息)

变化的道路(线段树分治&动态维护边信息)

[Cnoi2019]须臾幻境(妙妙题)

[USACO18FEB]New Barns P(动态维护直径)

EntropyIncreaser 与 动态图(动态维护割点&割边)

[BJOI2014]大融合(动态维护子树信息)

[SHOI2014]三叉神经树(定根 LCT&splay 上二分)

首都 (动态维护重心&splay 上二分)

详情可以参照这个 题单的前十七道题,我只是选了几道有代表性的出来。


Solution

关于这几道题中涉及的几个套路:

  • 维护边信息只需要新建一个点,然后连两条边即可。

  • 维护直径,需要用到的性质:新的直径的两个端点,一定是原来两颗树的总共四个端点中的两个。那么只要大力分讨最多六中情况即可。

  • 维护割点,只需要用 LCT 维护圆方树;维护割边,只需要维护边信息,每次区间打 tag。

  • 维护子树信息,需要存贮一个点 所有虚边 对应的儿子的子树信息,不同的地方在于 Access 和 link。

  • splay 上二分只要时刻记住 splay 的单调性是基于什么的,就不难。

  • 维护重心,关键在于重心的性质:以重心为根的树,根的所有儿子的子树大小不超过 \(\lfloor \frac{n}{2}\rfloor\)


Part 3 进阶题练习

[SDOI2017]树点涂色

会注意到一操作实质就是 LCT 中 Access 的操作,然后一个点到根的路径的贡献就是其经过的虚边条数。

于是就可以直接用线段树在虚实边切换的时候维护子树信息。当然需要注意:splay 里的儿子不是树上的儿子,只有虚边才是真实的树边。

Code


[ZJOI2018]历史

题意转化十分小清新:给定每个点的 Access 次数,求最大的虚实边转化次数。

在手摸的过程中,我们能发现:每条边第一次被 Access 遍历到的时候,一定会产生一次贡献,而之后,却要考虑是否来自两个不同的城市的崛起。

我们将边的贡献丢到儿子上。根据 LCT 的性质,两次 Access 会在它们 Lca 处产生一次贡献。

对于每个点,它们之间是相互独立的,可以单独计算贡献。具体的,对于每个点,两次来自于不同子树的点作为起始位置的连续的 Access 会造成贡献(自己出发的位置也可以产生贡献)。当某一颗子树内部的次数很多,超过总数一半的时候,用插板法可以得到当前的最大次数,为 \(2\times (\sum a_i -\max_{a_i})\)。除此之外,我们都能够使得两两相邻的产生一次贡献。

那么我们现在就是需要维护每个点,所有儿子的子树的权值和,以及最大权值,然后支持单点修。

注意到一个很好的性质:当被修改后,所有维护信息变化的点,它们若是在修改前后都是第二种状态(最大值小于等于一半),答案也会加上相同的值;对于都是前后都是第一种情况的,如果贡献在最大值对应的子树上,答案不变,否则则是最大值对应的子树改变的情况,比较复杂。

在分讨的过程中,我们注意到,只有两种状态相互替换,或者第二种情况中最大值对应子树改变的时候,答案计算非常麻烦。

这里我们联想到 LCT 的虚实链切换次数是 \(\log\) 次的,如果将这种转化对应到虚实链的切换,便能够使得复杂度正确。

于是我们就可以用 LCT 维护(雾),但是这个 LCT 和题意转化中的 LCT 不能混为一谈,我们只是利用 LCT 的性质分析出答案的计算方法,而后又发现这个东西可以利用 LCT 进行维护。

具体的,用实边表示第二种情况,那么所有答案的更改,与不变的实边无关,只需要在 Access 过程中进行虚实边判定即可。

代码调了三个小时,原因竟是 维护子树信息,splay 内调用子树大小应减去左儿子,也就是它的父亲的部分。

Code


这边还有一些和 SAM 有关的题,暂时咕咕咕。

top tree 的话 \(\cdots\) 咕咕咕咕咕咕。

posted @ 2021-04-04 21:09  zjjws  阅读(259)  评论(1编辑  收藏  举报