维护链信息
P1501 [国家集训队]Tree II
Solution
利用 $LCT$ 维护链上信息的经典题。
由于同时涉及到了加法和乘法,根据做线段树的经验,我们知道乘法优先,加法靠后。
剩余的普通的 $LCT$ 没什么区别。
Code
1 |
|
P3203 [HNOI2010]弹飞绵羊
Solution
我们将每个点向跳到的点连边,跳出的点向虚拟节点 $n+1$ 连边,可以发现一定构成了一棵树。
每次查询时,将 $u$ 到 $n+1$ 的链从原图中抽出来,那么答案就是 $sz-1$ 。
Code
1 |
|
P4332 [SHOI2014]三叉神经树
Solution
我们通过观察可以发现一个有趣的情况:
- 若是从 $0\rightarrow 1$ ,且 $x$ 指向的点的值为 $1$ ,那么会同它一起加 $1$ 的,只有到根结点的链上的连续的一段值为 $1$ 的点和最上方的点的父节点。
- 同理,从 $1\rightarrow 0$ ,且指向的点值为 $2$ ,减 $1$ 的连续段的值均为 $2$ 。
其他情况只需要单点加减即可。
判断一个序段中所有元素的值是否相等,我们可以通过这样的方法来做:
判断左半边的值是否等于右半边的值,如果相等,那么这一段的值和左右半边的值相等,否则设为极大值。
至于修改只需要区间修改即可。
那么剩下的问题就是怎么找出这一个连续段。
我们设计一个倍增算法,假设当前点为 $s$ ,当前是 $2^p$ 。
- 若存在 $fa[s][p]$ ,且 $s\rightarrow fa[s][p]$ 的值等于 $2/1$ ,那么另 $s=fa[s][p],p++$ 。
- 否则 $p—$ 。
初始条件为 $s=u,p=0$ ,终止条件为 $p=-1$ 。
这样我们就解决了这道题。
$LCT$ 时间复杂度: $O(n\log^2n)$ 。
树剖时间复杂度: $O(n\log^3n)$ 。
Code
由于当时还不太熟练,所以写了复杂度贼大的树剖
1 |
|
动态维护连通性&&双连通分量
P2542 [AHOI2005]航线规划
Solution
断边不好维护,但是加边很好维护。
题目要求的是两点之间桥的数量,其实就是求路径上包好的边双连通分量的个数减 $1$ 。
我们向里面加边时,如果两点已经连通,我们就将路径上的边双连通分量全部缩为一个点。
用并查集维护每一个点所在边双,每次查询都需要找到对应的编号。
还有就是在 $Access$ 的时候也需要 $find$ 一下。
Code
1 |
|
维护边权
P4172 [WC2006]水管局长
Solution
显然,题目要求动态维护原图的最小生成树。
我们首先还是考虑将操作离线下来,然后倒序操作。因为加边总比删边好做。
依次考虑加入每一条边,如果两点未连通,那么直接连接。
否则如果两点间的最大权值大于该边权值,那么断掉那条边,在加上该边。
问题就变成了怎么维护最大边权的边。
我们只需要将边拆成点,然后维护最大点权对应的编号即可。
Code
1 |
|
P4234 最小差值生成树
Solution
还是维护生成树,因为要最大值和最小值的差值最小,我们可以考虑枚举最大边或最小边,然后使得另一个尽量靠近。
考虑将边权从小到大排序,然后依次将边加入。
如果还未连通,那么直接连接,否则替换掉其中最小的那一条边。
最小值可以用一个 $multiset$ 来维护,但是也可以用指针维护。
Code
1 |
|
维护子树信息
P4219 [BJOI2014]大融合
Solution
利用 $LCT$ 维护子树信息模板题。
用 $LCT$ 维护子树和一般的写法有一些不同。
- 额外维护了一个数组 $s1$ 表示虚子树的信息,在 $pushup$ 时也要加上。
- 在 $Access$ 时,由于改变了子树的虚实,需要及时更改。
- 在 $Link$ 时,会给 $y$ 多一条虚边,要及时加上,但是直接加会使 $y$ 的父节点都要加,可以先 $Make_root(y)$ 再改。
然后答案就是 $Split(x,y)$ 后, $x$ 的虚子树大小加 $1$ 乘上 $y$ 的虚子树大小加 $1$ 。
Code
1 |
|
我们的 CPU 遭到攻击
Solution
套路题?
我们分别维护以下变量:
- $lans$ :一个 $splay$ 子树中的所有黑点到其子树中深度最浅的点的距离和。
- $rans$ :一个 $splay$ 子树中的所有黑点到其子树中深度最深的点的距离和。
- $ians$ :一个点的所有虚儿子所在的 $splay$ 中的所有黑点到其对应的虚儿子的距离。
- $ds$ :一个 $splay$ 中的黑点个数。
- $ids$ :一个点的所有虚儿子所在的 $splay$ 中的黑点个数。
那么询问的答案就是 $x$ 为根时, $lans_x$ 的值。
因为有翻转操作,所以最深会变为最浅,最浅会变为最深,直接交换 $lans_x,rans_x$ 即可。
注意 $pushup$ 时,由于 $x$ 和 $lc$ 所在的 $splay$ 子树中的黑点,还没有走到当前的最深/最浅,我们需要将这一段加上。
同时注意在 $Access$ 和 $Link$ 时更新 $ians,ids$ 即可。
Code
1 |
|
P4299 首都
Solution
动态维护树的重心。
有两种做法:
启发式合并
每次将小的合并到大的上面去,由于重心的性质,每次重心要么不变,要么向新加的叶子处移动一格,用 $LCT$ 维护即可。
时间复杂度: $O(n\log^2 n)$ 。
$Splay$ 树上二分
树的重心有一个很好的性质:两颗树合并后,新的重心一定在原来两棵树的重心连线上。
所以我们可以将原来的两个重心 $Split$ 出来,然后在上面二分。
结束条件是左右子树的大小均不超过总大小的一半。
由于可能有两个重心,所以需要找完,还有每次记得 $pushdown$ 。
Code
1 |
|