CF73D题解

发布时间 2023-11-17 07:17:49作者: OIer_xxx2022

首先将题意转化一下,假设我们在第一步中将原图划分成了 \(p\) 个连通块,计第 \(i\) 连通块大小为 \(siz_i\),那么每个连通块可以向外连 \(\min{(k,a_i)}\) 条边。而使原图联通显然至少需要 \(p-1\) 条边,形式话的来讲,我们能在第二步使图联通这个条件等价于 \(\sum{\min {(siz_i,k)}} \ge 2(p-1)\)

这样的话我们再来考虑第一步,我们需要最大化左边,最小化右边。此时由于这个式子只与各个联通块的大小和连通块的数量有关,我们可以用并查集求出初始图的连通块信息,将加边操作转化为联通块的合并,联通块合并使用优先队列维护即可,时间复杂度 \(O(m+n\log{n})\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
inline int read(){
	int f=1,w=0;
 	char c=getchar();
 	while(c<'0'||c>'9'){
 		if(c=='-')	f=-1;
 		c=getchar();
	}
	while(c>='0'&&c<='9'){
	 	w=(w<<1)+(w<<3)+(c^48);
	 	c=getchar();
	}
	return f*w;
}
int fa[N];
int find(int x){
	if(fa[x]==x)	return x;
	return fa[x]=find(fa[x]);
}
void merge(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y)	return;
	fa[x]=y;
}
int a[N];
int n,m,k;
priority_queue <int, vector<int> , greater <int> > q;
int main(){
	n=read();
	m=read();
	k=read();
	for(int i=1;i<=n;i++)	fa[i]=i;
	for(int i=1;i<=m;i++){
		int x,y;
		x=read();
		y=read();
		merge(x,y);
	}
	for(int i=1;i<=n;i++){
		a[find(i)]++;
	}
	int cnt=0;
	int ans=0;
	for(int i=1;i<=n;i++){
		if(a[i]){
			q.push(a[i]);
			cnt++;
			ans+=min(a[i],k);
		}
	}
	if(ans>=2*(cnt-1)){
		printf("0\n");
		return 0;
	}
	int res=0;
	while(q.size()>=2){
		int x=q.top();
		q.pop();
		int y=q.top();
		q.pop();
		cnt--;
		ans-=min(x,k);
		ans-=min(y,k);
		ans+=min(x+y,k);
		res++;
		if(ans>=2*(cnt-1)){
			break;
		}
		q.push(x+y);
	}
	cout<<res<<endl;
	return 0;
}