Kruskal 重构树
一个比较冷门的算法。
Kruskal 重构树
在 的过程,并做这样一个操作:
- 从小到大遍历所有边,设当前边两端为 ,;
- 判断 、 是否在同一并查集;
- 若不在,新建一个点权为这条边边权的节点 ,将 、 分别于 连边,并把 、 的并查集合并到 上。
for (int i = 1; i <= n; i ++) {
int p = getfa(e[i].x), q = getfa(e[i].y);
if (p == q) continue;
v[++ tot] = e[i].v;
e[tot].push_back(p), e[p].push_back(tot);
e[tot].push_back(q), e[q].push_back(tot);
fa[p] = fa[q] = fa[tot] = tot;
}原来的点点权为负无穷。
这样我们就得到了一棵树,这棵树就是 Kruskal 重构树。这棵树有什么性质呢?
- 这棵树有 个点, 以第 个点为根,该树有 个叶子节点,叶子节点都是原来的点,因为合并操作进行了 次,原来的点显然是叶子;
- 树上任意两点 的点权就是原图中这两点路径上最长边的最小值。这个也很显然,我们是从小到大操作边的,所以显然深度越小的点点权越大;
- 对于原图上的一个点,它能用权值 的边到达的点,就是它在树上深度最小的点权 的祖先的子树内的点。这个也很显然。
根据这些性质(尤其是 2、3), 重构树可以很好的把图上的问题转化为树上的问题。
Kruskal 重构树
https://ybwa.github.io/p/53115/