克鲁斯卡尔重构树

什么是Kruskal重构树?

Kruskal重构树,和Kruskal算法的思想差不多,就是在这个过程中建出一个有着非常优秀的性质的数据结构,这是一个非常少见和小众的算法,但是如果碰到了合适的题目,就会体现出其优越性。

实现过程

先将边权排序(排序的方式决定了这颗重构树的性质),我们把边排完序之后依次遍历每条边,如果这条边两端的\(u,v\)不在同一并查集内,那么就新建一个节点\(node\),我们设\(u,v\)两点在并查集中的根分别为\(root_u,root_v\),那么我们连接\(node,root_u\)\(node,root_v\),然后用并查集更新\(root_u,root_v\)\(father\)都更新为\(node\),最后把这个点的点权相应的记录为这条边的边权,一直这样不断的连边,那么我们就建出来了一颗Kruskal重构树。

性质

知道了这东西是怎么实现的,我们还需要知道这玩意有什么性质然后才能知道做什么题能用到
首先,这个玩意是一棵树嗯没错,而且还是一颗二叉树。

u->v路径上边权的最大值最小

我们要在一张图上找到\(u,v\)两点之间的一条路径,使得这条路径满足最大值最小(最大瓶颈路,NOIP2017货车运输)。
传统做法可以建一颗最小生成树然后倍增求最小值,但是我们也可以用Kruskal重构树来比较简单的解决这个问题
我们按照边权从小到大排序之后建Kruskal重构树,然后找到点\(u\)和点\(v\)\(LCA\)的权值就是路径的最小的最大值
如何证明呢?我们感性理解一下,在Kruskal重构树中,深度越大的边一定边权越小,所以我们找到\(u,v\)两个点之后,这两个点能够相互到达的路径是唯一的,并且在LCA处的权值是最大的,所以LCA的权值就是我们要求的边权

例题

NOI2018D1T1 归程

因为每天开始的时候车的位置都会被重置一次,所以我们对于每次询问都可以在起点进行一次\(bfs\),然后答案就是这些点中到\(1\)号点距离最小的点.
但是这样...显然过不了...发现每次进行询问的时候都去\(bfs\)一遍显然太慢了,而且这道题为强制在线,也不能按照这些询问的海拔排序.
那么我们怎么办呢?
根据标题,我们可以选择\(Kruscal\)重构树来解决掉这道题.
首先我们发现,\(Kruscal\)重构树满足大根堆的性质,那么满足海拔大于水位线的边组成的点一定是某一颗子树.
然后我们可以进行一次堆优化的\(Dijkstra\)进行预处理,然后把\(1\)号点到每个点的最短路的长度记为重构树上新的点的点权.
然后对于每次查询,我们的任务就变成了查询某颗子树中的叶子的权值最小值,而且是静态的.显然可以\(log\)的复杂度随便搞一搞.

posted @ 2021-10-09 12:33  兮水XiShui  阅读(393)  评论(0)    收藏  举报