Kruskal重构树 学习笔记
Kruskal重构树 学习笔记
Kruskal重构树
基本思想
对于一个无向图,将每条边按边权升序排序。对于每一条边,若该边两点不在同一个连通块,新建一个节点向该边的两点建边,点权即为原边边权。最后建成一棵重构树。
举例:(原图来自rui_er Kruskal 重构树学习笔记)


性质
1.重构树是一棵有 \(n\) 个叶子节点,每个非叶子节点都有左右儿子的二叉树。重构树的点数为 \(2n-1\)。
2.重构树的点权符合大根堆的性质。
3.原图中两点间所有简单路径的最大边权最小值,等于最小生成树上两点之间边权最大值,等于重构树上两点 LCA 的点权。
4.到点\(x\)的简单路径上的最大边权最小值 \(\le k\) 的所有节点 \(y\) 均在重构树上的某棵子树内,且恰为该子树内的所有叶子节点。
代码实现
通过类kruskal求最小生成树和并查集实现。
下面代码示例为 Luogu P2245星际导航。求两点 \(x,y\) 间所有简单路径的最大边权最小值,可直接通过性质3求解。
void kruskal(){
sort(e+1, e+1+m, cmp);
for(int i = 1;i <= n;i++) f[i] = i;
for(int i = 1;i <= m;i++){
int fx = find(e[i].x), fy = find(e[i].y);
if(fx == fy) continue;
cnt++, f[fx] = f[fy] = f[cnt] = cnt, a[cnt] = e[i].w;
add(cnt, fx); add(fx, cnt);
add(cnt, fy); add(fy, cnt);
}
for(int i = 1;i <= cnt;i++){
if(!vis[i]){
int fat = find(i);
dfs1(fat, 0);
dfs2(fat, fat);
// 树剖求lca
}
}
}
void solve(){
int q = read();
while(q--){
int x = read(), y = read();
if(find(x) != find(y)) write(-1);
else write(a[lca(x, y)]);
}
}
例题
洛谷kruskal重构树题单
更多题待补。

浙公网安备 33010602011771号