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;
}
posted @ 2020-09-09 22:05  JY_Chen  阅读(100)  评论(0)    收藏  举报