题解 CF73D 【FreeDiv】
pythoner713 · · 题解
假设我们在第一步中已经随便连了一些边,那么怎么判断是否可以通过操作二使图联通呢?
经过操作一后,设当前图中的联通块大小分别是
乘以
那么现在正解就呼之欲出了,第一步的连边无非是为了合并原图连通块,达到减小
#include<bits/stdc++.h>
#define nb 1000010
using namespace std;
int ans, d, n, m, k, E, fa[nb], size[nb];
priority_queue<int, vector<int>, greater<int>> q;
int find(int x){
while(x != fa[x])
x = fa[x] = fa[fa[x]];
return x;
}
int main(){
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m >> k;
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 0, u, v; i < m; i++)
cin >> u >> v, fa[find(u)] = find(v);
for(int i = 1; i <= n; i++) size[find(i)]++;
for(int i = 1; i <= n; i++){
if(find(i) == i) q.push(size[i]), d++;
E += min(k, size[i]);
}
while(1){
if(E >= 2 * d - 2){
cout << ans;
return 0;
}
ans++;
int u, v;
u = q.top(), q.pop();
v = q.top(), q.pop();
d--, E -= min(u, k) + min(v, k);
E += min(k, u + v);
q.push(u + v);
// E 即为不等式左侧的值
// 每次贪心地取两个最小的连通块合并
// 一旦有 E >= 2(d - 1) 说明可以进入操作二, 输出答案
}
return 0;
}