连边的不能在一起那么最直观的思路就是求一个补图再求联通块个数与大小
但是补图应该是个稠密图,那就直接找和某一个点在原来的图里没有连边的并且不属于别的联通块的点。
至于复杂度不能接受的问题,用链表来保存所有点,加入某个联通块的点从链表中删掉就不会重复选了
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#define N 100005
using namespace std;
int read()
{
int a=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}
return a*f;
}
vector<int>a[N];
int n,m,ans=0;
int l[N],r[N],vis[N],mark[N],hav[N]={0};
void del(int x)
{
r[l[x]]=r[x];
l[r[x]]=l[x];
vis[x]=1;
}
queue<int>Q;
void bfs(int x)
{
while(!Q.empty()) Q.pop();
Q.push(x);
while(!Q.empty())
{
int to=Q.front();Q.pop();
++hav[ans];
for(int i=0;i<a[to].size();++i) mark[a[to][i]]=1;
for(int i=r[0];i;i=r[i])
if(!vis[i]&&!mark[i]) Q.push(i),del(i);
for(int i=0;i<a[to].size();++i) mark[a[to][i]]=0;
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
a[x].push_back(y);
a[y].push_back(x);
}
for(int i=0;i<=n;++i) l[i]=i-1,r[i]=i+1;
r[n]=0;
for(int i=1;i<=n;++i)
if(!vis[i])
{
++ans;
del(i);
bfs(i);
}
sort(hav+1,hav+ans+1);
printf("%d\n",ans);
for(int i=1;i<=ans;++i) printf("%d ",hav[i]);
return 0;
}