有一张完全图,(n) 个节点,有 (m) 条边的边权为 (1),其余的都为 (0),这 (m) 条边会给你。问你这张图的最小生成树的权值。
Solution
将 (1) 边视为不存在,那么最后的答案就是 (0) 边形成的连通块数 (-1)
顺序扫描所有点,对于点 (i),枚举由 ([1,i-1]) 已经形成的集合 (j),如果 (i) 向 (j) 连的边数小于 (j) 的大小,那么就表明一定有 (0) 边,于是将 (i) 所在集合与集合 (j) 合并
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 500005;
int n,m,t1,t2,fa[N],sz[N],bel[N];
vector <int> g[N];
int find(int p) {
return p==fa[p] ? p : fa[p]=find(fa[p]);
}
void merge(int p,int q) {
p=find(p); q=find(q);
if(p!=q) {
fa[p]=q;
sz[q]+=sz[p];
}
}
signed main() {
ios::sync_with_stdio(false);
vector <int> st;
cin>>n>>m;
for(int i=1;i<=m;i++) {
cin>>t1>>t2;
g[max(t1,t2)].push_back(min(t1,t2));
}
for(int i=1;i<=n;i++) {
fa[i]=i;
sz[i]=1;
}
for(int i=1;i<=n;i++) {
map<int,int> cnt;
for(int j:g[i]) cnt[find(j)]++;
for(int j:st) {
if(find(i)==find(j)) continue;
if(cnt[find(j)]<sz[find(j)]) merge(i,j);
}
if(find(i)==i) st.push_back(i);
}
int ans=0;
for(int i=1;i<=n;i++) if(find(i)==i) ++ans;
cout<<ans-1;
}