给出一个 \(n\) 个点,\(\frac{n(n-1)}{2}-m\) 的无向图,以补图的形式输入,问图中有多少连通分量以及每个连通分量有多少点。
考虑增量构造,依次加入每一个点,维护已有的连通块。对于每一个新加入的带点,考察其余某一个已有的连通块是否连通,这只需要数一下边的条数即可,如果连通则并查集维护一下。容易发现连通块数量一定是很小的。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int fa[N],sz[N],n,m,t1,t2;
vector <int> g[N];
int find(int p)
{
return p==fa[p] ? p : fa[p]=find(fa[p]);
}
set<int> s;
void merge(int p,int q)
{
p=find(p);
q=find(q);
if(p>q) swap(p,q);
if(p!=q) sz[q]+=sz[p],fa[p]=q;
}
signed main()
{
//ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
fa[i]=i;
sz[i]=1;
}
for(int i=1;i<=m;i++)
{
cin>>t1>>t2;
if(t1>t2) swap(t1,t2);
g[t2].push_back(t1);
}
for(int i=1;i<=n;i++)
{
map<int,int> mp;
for(int j:g[i])
{
mp[find(j)]++;
}
vector <int> vec;
for(int j:s)
{
if(find(j)==j && mp[j]<sz[j])
{
vec.push_back(j);
}
}
for(int j:vec)
{
merge(i,j);
}
vec.clear();
for(int j:s)
{
if(find(j)!=j) vec.push_back(j);
}
for(int j:vec)
{
s.erase(j);
}
if(find(i)==i) s.insert(i);
/*for(int j:s)
{
cout<<j<<",";
}
cout<<endl;*/
}
multiset <int> ans;
for(int i:s)
{
ans.insert(sz[i]);
}
cout<<ans.size()<<endl;
for(int i:ans)
{
cout<<i<<" ";
}
}
[CF920E] Connected Components? - 思维,并查集,STL
原文:https://www.cnblogs.com/mollnn/p/13637026.html