线段树分治&可撤销并查集
可撤销并查集
按时间顺序用一个栈维护合并信息,撤销时从栈顶弹出合并信息,恢复原状态。
并查集查找祖先时 不能路径压缩,只能按秩合并。
例题:
[ABC302Ex] Ball Collector
容易想到将 \(A_i\) 和 \(B_i\) 之间连边。
遍历整棵树,用可撤销并查集维护图。
为了进一步求得答案,需要注意到该结论:对于一个连通块,对当前答案的贡献为 \(\min(\text{点数}, \text{边数})\)。([ARC111B] Reversible Cards)
证明可以考虑从树的特殊情况出发,添加一条返祖边,分析贡献的变化。
于是简单地维护这两个量和答案即可。
Warning:在实现上的注意:
之前写可撤销并查集时只用栈维护了合并两个连通块时的操作(由于不是路径压缩,因此父亲在一段时间内是固定的,你甚至可以只记录大小较小的连通块的祖先编号),并没有把每一步操作都记录下来,这是因为我们需要的信息只与连通块内的点有关,因此不需要知道连通块内连接的具体形态。但在这道题里,我们需要查询边的信息,因此需要把每一步操作都存进栈里。
线段树分治
xht 的题解对该算法的叙述精辟而清晰:
考虑这样一个问题:
- 有一些操作,每个操作只在 \(l \sim r\) 的时间段内有效。
- 有一些询问,每个询问某一个时间点所有操作的贡献。
对于这样的询问,我们可以离线后在时间轴上建一棵线段树,这样对于每个操作,相当于在线段树上进行区间操作。
遍历整颗线段树,到达每个节点时执行相应的操作,然后继续向下递归,到达叶子节点时统计贡献,回溯时撤销操作即可。
这样的思想被称为线段树分治,可以在低时间复杂度内解决一类在线算法并不优秀的问题。
例题:(没放板题)
线段树分治与可撤销并查集
P5631 最小mex生成树
枚举答案 \(x\),将所有权值为 \(x\) 的边删除,若剩下的边能够形成生成树(即图联通),说明原图上至少存在一棵生成树的 \(mex\) 值 \(\le x\),即答案 \(\le x\)。则最小使图连通的 \(x\) 即为答案。
将边权视作时间进行分治。将边权为 \(x\) 的出现时段分成 \([0, x - 1]\) 和 \([x + 1, \infin]\),最小使图连通的时间点即为答案。
空间复杂度 \(O(m\log{w})\),时间复杂度 \(O(m\log{n}\log{w})\)。(?
CF1681F Unique Occurrences
有了上面那道题的经验,这里仍然考虑 将边权视作时间进行分治。
对于颜色 \(c\),将所有权值为 \(c\) 的边删除后形成若干连通块,原树上权值为 \(c\) 的边 \(x\) 所连的两个连通块的乘积即为通过 \(x\) 做出的贡献。
CF1140F Extending Set of Points
难得独立做出来 *2600。按时间分治,关键是如何维护答案。
经典套路,将二维平面上的点 \((x, y)\) 视作 \(x\) 与 \(y + N\) 之间连无向边,则答案为所有连通块内横坐标点数与纵坐标点数的乘积之和。
由于递归到叶子节点时统计答案的时间复杂度过高,可以 在并查集的合并与撤销时维护答案。
[ABC163F] path pass i
将点权视作时间进行分治,用线段树分治维护连通块信息。
如果按原题意操作,发现线段树递归到叶子节点时不方便统计答案,因此可以容斥一下,去求不包含颜色 \(c\) 的路径数 \(cnt\)。
去掉所有端点权值为 \(c\) 的边,每个大小为 \(x\) 的连通块内对 \(cnt\) 贡献 \(\binom{x}{2} + x\)(注意此题中单点也算一条路径),但是切掉边后形成的颜色为 \(c\) 的单点不会做贡献,因此算的时候要把这部分去掉。
仍然是在并查集合并和撤销的过程中维护答案。
时间复杂度 \(O(n\log^{2}{n})\),但此题有线性做法。