📚【模板】Kruskal重构树
构造较为简单。
性质较为有用。
我们在跑 Kruskal 最小生成树
的过程中,每加入一条边,就把这条边的两端所在的根节点连接到一个新的节点上,并使新的节点成为根节点,给这个节点赋予与这条边一样的权重。便构造出了 Kruskal 重构树
。
#include <iostream>
#include <algorithm>
const int N = 1e5+10;
int n, m;
int anc[N<<1];
void init(int initial_size) {
for(register int i = 1;i <= initial_size;++i)
anc[i] = i;
}
int get_anc(int x) {
if(x != anc[x])
anc[x] = get_anc(anc[x]);
return anc[x];
}
void merge(int x,int y) {
if(get_anc(x) != get_anc(y))
anc[anc[x]] = anc[y];
}
bool dsu(int x,int y) {
return get_anc(x) == get_anc(y);
}
struct EDGE {
int f, t, next;
int w;
EDGE ()
: f(0), t(0), next(0), w(0) {}
EDGE (int _f,int _t,int _next,int _w)
: f(_f), t(_t), next(_next), w(_w) {}
} edge_map[N], edge_ksk[N<<2];
int head_ksk[N<<1], ksk_edge_tot;
void add_edge_ksk(int f,int t,int w) {
edge_ksk[head_ksk[f] = ++ksk_edge_tot] = EDGE(f,t,head_ksk[f],w);
}
int ksk_node_tot;
int val[N<<1], pid[N<<1];
void kruskal_reconstruct() {
std :: sort(edge_map+1,edge_map+m+1,[](const EDGE _x,const EDGE _y) {return _x.w < _y.w;});
ksk_node_tot = n;
init(n<<1);
for(register int i = 1;i <= m;++i)
if(!dsu(edge_map[i].f,edge_map[i].t)) {
val[++ksk_node_tot] = edge_map[i].w;
merge(anc[edge_map[i].f],ksk_node_tot);
merge(anc[edge_map[i].t],ksk_node_tot);
pid[anc[edge_map[i].f]] = ksk_node_tot;
pid[anc[edge_map[i].t]] = ksk_node_tot;
add_edge_ksk(anc[edge_map[i].f],ksk_node_tot,1);
add_edge_ksk(ksk_node_tot,anc[edge_map[i].f],1);
add_edge_ksk(anc[edge_map[i].t],ksk_node_tot,1);
add_edge_ksk(ksk_node_tot,anc[edge_map[i].t],1);
}
std :: cerr << ksk_node_tot << std :: endl;
}
int main() {
scanf("%d %d",&n,&m);
for(register int i = 1;i <= m;++i)
scanf("%d %d %d",&edge_map[i].f,&edge_map[i].t,&edge_map[i].w);
kruskal_reconstruct();
for(register int i = 1;i <= ksk_node_tot;++i)
printf("%d : %d %d\n",i,pid[i],val[i]);
return 0;
}
- 不能进行按秩合并,否则会破坏并查集的根同时作为子树的根的性质。
Kruskal 重构树
有性质:原图中两个点之间的所有简单路径上最大边权的最小值 = 最小生成树
上两个点之间的简单路径上的最大值 = Kruskal 重构树
上两点之间的 LCA 的权值。
例题先咕。