MST Unification
给定一个有n个点,m条边的无向连通图,每条边有边权。
定义一次操作为:选择一条图中的边,并将其权值+1。
试求最小的操作次数,使得操作后的图的最小生成树是唯一的。
1<=N<=2e5
n-1<=m<=2e5
Sol:
考虑在使用krustal进行加边操作
在加边的时候,我们会进行排序操作,对吧
于是在将所有边升序排列出来后,将具有相同权值的边找出来.
检查下这些边能连通多少个块,计为ans,例如下图
其可连通3个不同的块
接下来我们进行实际操作,每次加边进行,如果发现两个点不在一个集合中
则当前边是可以直接使用的,于是ans--
最终发现有一条边是不能加进去的,于是这条边的权值就是要按题意进行累加的。
大家可自行处理下这个样例
会发现使用边权为3的边
由于1与5已在一个集合中了,于是只连通2个集合,ans的值为1
在实际加边操作中,也就只能使用1--2这条边了。
最终这个样例的MST是唯一的。
#include<bits/stdc++.h> using namespace std; const int NN=2e5+4; struct node { int u,v,w; bool use; bool operator<(const node&it)const { return w<it.w; } }edge[NN]; int fa[NN],maxx[NN]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); sort(edge+1,edge+1+m); int ans=0,i=1; while(i<=m) { int j=i; while(edge[i].w==edge[j].w) j++; for(int k=i;k<j;k++) if(find(edge[k].u)!=find(edge[k].v)) ans++; for(int k=i;k<j;k++) { int fu=find(edge[k].u),fv=find(edge[k].v); if(fu!=fv) { ans--; fa[fv]=fu; } } i=j; } printf("%d",ans); return 0; }