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重构树题单
更多题待补。

posted @ 2025-03-15 15:36  Hirasawayuiii  阅读(18)  评论(0)    收藏  举报