Kruskal 重构树
定义
从构建的过程来定义。
在 kruskal 算法最小生成树的过程中,我们从小到大得到了 \(n - 1\) 条最小生成树上的边。根据这些边我们重新构造一颗树,具体的,依次遍历上述 \(n - 1\) 条边,对于当前遍历到的边 \((u, v, val)\)(表示节点 \(u\) 和节点 \(v\)之间有一条边权为 \(val\) 的边),我们新建一个点权为 \(val\) 的节点 \(t\),并建立无权边 \((t, root(u))\) 和 \((t, root(v))\),\(root(u)\) 表示 \(u\) 当前所在树的根节点,当然连边后 \(root(u) = root(v) = t\)。依据上述过程我们得到一颗共有 \(2n - 1\) 个节点的树,这棵树就是 kruskal 重构树。
实现
// 并查集
int get(int u) {
return u == fa[u] ? u : (fa[u] = get(fa[u]));
}
bool merge(int u, int v) {
int fu = get(u), fv = get(v);
fa[fv] = fu;
return fu != fv;
}
void solve() {
// code ...
// edge 存排好序的边
int cnt = n;
for (auto &[u, v, value] : edge) {
if (merge(u, v)) {
cnt++; // 新增节点的编号
fa[u] = fa[v] = cnt;
val[cut] = value;
g[cnt].push_back(u); // 建立无权边
g[cnt].push_back(v);
}
}
// code ...
}
性质
原图中两个点之间的所有简单路径上最大边权的最小值 = 最小生成树上两个点之间的简单路径上的最大值 = kruskal 重构树上两点之间的 LCA 的权值。
第二个等号可以这样理解: kruskal 重构树上两点的 LCA 代表的是这样一条边,在加入这条边前两点不连通而加入这条边后两点才连通。因为在建树时我们是从小到大加边,所以 LCA 的值就应该是最小生成树上两个点之间的简单路径上的最大值。
ABC394 G 可利用上述性质
浙公网安备 33010602011771号