kruskal 重构树

这个算法是用来解决:求图上两点的路径,最大/小的边的相关信息


例题引入:

传送门

在之前学习 MST 中,我们了解到,当用 kruskal 生成一棵 MST,它同时满足为瓶颈生成树(即使最小化最大边)

因此我们可以在 MST 找出询问点 \((u,v)\) 的路径,求最大边

但这个似乎不太优秀(?那就用重构树做吧!

流程:

先新建 \(n\) 个集合,集合 \(i\) 的初始根的编号为 \(i\),然后正常按照 kruskal 建生成树;

在生成树加入边 \((u,v)\) 时,新建一个结点 \(p\) ,它的点权设为加入的边权;

\(p\) 的左右儿子分别设为 \(u\) 所在集合的根,\(v\) 所在集合的根;

再将这两个集合合并为一个新的集合,新集合的根为 \(p\)

这样我们会得到一个大根堆

当询问两点 \((u,v)\) 时,大根堆上的 \(LCA(u,v)\) 的权值就是答案

代码


进阶

P4768 [NOI2018] 归程

显然,我们一定是先坐汽车到某个点,然后在步行到 \(1\) 号结点

考虑按海拔从大到小将边排序,并按套路建出重构树,这时得到的是关于海拔的小根堆

对于一个小根堆上的点 \(u\),说明当水位线小于 \(val[u]\) 时,\(u\) 子树内的叶子对应的原结点可以互相乘车到达

跑一遍以 \(1\) 为起点的 Dijkstra

当询问 \((u,h)\) 时,我们从 \(u\) 出发向上跳,跳到最浅的 \(val>h\) 的点,输出这个点的子树中到 \(1\) 号结点的最小 dis 即可

可以用倍增实现

代码

posted @ 2022-09-14 11:08  zuytong  阅读(87)  评论(0编辑  收藏  举报