Codeforces 1108-Problem-F MST Unification
Codeforces 1108-Problem-F
MST Unification
题目链接:https://codeforces.com/contest/1108/problem/F
题目大意
给你一张图,
设其最小生成树的边权和为k
你可以进行的唯一操作为给某条边的权值加上1,
要求操作后
该图的最小生成树唯一且最小生成树边权和依然为k。
求最小生成树的Kruskal算法,
会把边按边权排序,然后逐条插入图中
我们可以考虑将这些边权相同的边放在一起考虑
且设这些边权相同的边数量为m,
这些边的端点点集为V
首先,插入完这若干条边权相同的边后
这若干条边所涉及到的所有联通块都被连到了一起
所以边权相同的边的顺序
对最终答案是没有影响的,
并且
必然会有一些边的两个端点,
在插入这m条边之前就已经是一个联通块内的了,
这样的边对最小生成树必然是没有任何贡献的,
我们记这样的边数量为s,
即真正有用的边有\((m-s)\)条
如果设在插入这m条边前,
V中的点组成了n个联通块,那么,
联通了这n个联通块的边,就只有\(n-1\)条了。
题目要求最小生成树唯一,
就必须将其余的\((m-s)-(n-1)\)条边加上1,
以消除它们的贡献
同时设在加入这m条边前
Code
#include <cstdio>
#include <cstring>
using namespace std;
int u[200010],v[200010],w[200010],f[200010];
void qsort(int l,int r)
{
int i=l,j=r,mid=w[(l+r)/2],t;
while(i<=j)
{
while(w[i]<mid) i++;
while(w[j]>mid) j--;
if(i<=j)
{
t=u[i];u[i]=u[j];u[j]=t;
t=v[i];v[i]=v[j];v[j]=t;
t=w[i];w[i]=w[j];w[j]=t;
i++;j--;
}
}
if(i<r) qsort(i,r);
if(l<j) qsort(l,j);
}
int findf(int x)
{
if(f[x]==x) return x;
else return f[x]=findf(f[x]);
}
int main()
{
//freopen("MST.in","r",stdin);
//freopen("MST.out","w",stdout);
int n,m,i,j,noww,usei,nowi,m1,m2;
int ans=0;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d%d%d",&u[i],&v[i],&w[i]);
qsort(1,m);
for(i=1;i<=n;i++) f[i]=i;
i=1;
while(i<=m)
{
noww=w[i];
usei=nowi=0;
j=i;
while(w[j]==noww&&j<=m)
{
m1=findf(u[j]);m2=findf(v[j]);
if(m1==m2) usei++;
j++;
}
while(w[i]==noww&&i<=m)
{
m1=findf(u[i]);m2=findf(v[i]);
if(m1!=m2) usei++,f[m1]=f[m2];
nowi++;
i++;
}
ans+=nowi-usei;
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号