参考:
- 老师讲解
- Fighting_Peter 的文章
其实Kruskal重构树并不难。
概览
首先,Kruskal重构树,顾名思义就是把整棵树重构。
并且其是基于Kruskal算法的。
它能解决很多问题,并且变种很多。
但我们先从基础的实现说起。
实现过程
我们考虑,在Kruskal算法里,我们每次会合并两个并查集集合。
准确来说是在两个点 $u$、$v$ 之间加一个边权为 $w$ 的无向边。
那么,我们就考虑,在重构树里,我们找到 $u$ 和 $v$ 分别所在的子树,把这两个子树的根拎出来,设为 $u’$ 和 $v’$。
然后,我们就新建一个点 $w$,然后把 $u’$ 和 $v’$ 的父亲设为 $w$。
此时我们就得到了另外一棵树。
比如说这个例子:
而在代码中,我们需要给这些方点一个别的编号,而不是以 $w$ 作为编号,否则会重,并且会炸。
特性
我们讲一些Kruskal重构树的特性:
-
这棵树一定是二叉树。
-
原树中的点放到重构树上一定是叶子,重构树上其他点都是原树中的边权。
-
节点个数一定是 $2n-1$,且 $2n-1$ 一定是根。
-
如果是最小生成树,那么这棵重构树一定是大根堆1,否则是小根堆。
-
原图中两个点 $u$、$v$ 之间所有路径上的边权最大值的最小值,就是该图的最小生成树重构树上,$u$ 和 $v$ 的LCA的权值。
尚未想到证明方式
-
对于一个最小生成树上的点 $x$,其只通过(边权)不超过 $v$ 的边,能到的点集;和 $x$ 在重构树上深度最浅的、权值 $\leq v$ 的点 $y$ 的子树内(叶子)节点集合,是一样的。
这里稍微证明一下。
就是我们根据上面的性质,可以发现,设后者对应集合为 $S$,那么显然 $S$ 内的点,和 $x$ 点,的LCA的权值一定不超过 $v$,显然。
那根据上面那个性质,LCA不超过 $v$,那么路径上的最大权值最小值一定也不超过 $v$。
既然如此,就证毕了。
解决题型
题型1
Kruskal重构树本来就是为了解决时间戳问题的。
题型2
比如“混合药剂”(只是猜测,因为我找不到这道题的来源)这道题就是Kruskal重构树的变种。
还比如说在正常情况下,如果要求如上面所说的「原图中两个点 $u$、$v$ 之间所有路径上的边权最大值的最小值」,那么其实可以用最小生成树。
不过这样得要写路径上最大的边权,需要用倍增。
为了防止部分人不了解,或者对下述文字出现误解或不理解,此处解释一下如何做这个倍增的。
正常情况下,如果是序列内一个区间的最大边权,那么可以用RMQ,也就是ST表(本质上就是倍增)求出。
但如果放到树上,就得稍微改一下了。
定义两个状态 $up_{x,i}$ 表示 $x$ 点向上走 $2^i$ 条边后,到达的点的编号。
还有 $ma_{x,i}$ 表示 $x$ 点往上的 $2^i$ 条边的最大边权。
那么,可以得到 $ma_{x,i}=\max(ma_{x,i-1},ma_{up_{x,i-1},i-1})$。
而求一条路径上的边权最大值,我们可以求出这条路径两端点的LCA。
随后我们把这条路径分成左右两段2处理。
然后可以发现,这个取 $\max$ 操作是可重的。
但是尽管如此,我们还得倍增,而不是像ST表一样直接求值。
具体而言,我们看 $len=dep_u-dep_t$ 的值,即 $u \to t$ 的路径长度。
然后,我们找到这个值的 $\log_2$ 值,即 $lg=\big\lfloor \log_2 (dep_u-dep_t) ~\big\rfloor$。
随后,我们可以发现,我们得求出 $u$ 往上 $len-2^{lg}$ 条边的点。
因为只有在知道这个点 $x$ 后,我们才能确定 $\max$ 的第二项。
最后我们可以直接求出答案 $\max(ma_{u,lg},ma_{x,lg})$。
那么,可以发现,这个复杂度是 $\log$ 的,跑得慢,细节多~~(不过实际上不多)~~。
不过根据上述特性,我们可以用Kruskal重构树做。
我们使用RMQ可以 $O(1)$ 在线求出任意两点的LCA值,即可 $O(1)$ 回答询问。
就是这样,我们就可以把那个 $\log$ 去掉了。
不过这样代码会长一些(我觉得实际上会长很多,不过以消掉一个 $\log$ 为获利也是很值的)
其他题型待补充
待补充