bzoj1098
对于每个对点,如果他俩没有直接连边,就必须放在一个楼里,所以显而易见的就是要求补图的联通块。
但是没办法直接把补图建出来。
可以用链表来维护之间没有访问过的集合。
每次从未访问的点中选一个,找没访问的集合中不与他相连的点有哪些,然后删去这些点,表示已经访问过了,并且继续找他们没有访问过的节点即可。
#include <iostream>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=4000005;
int n,m,nxt[N],to[N],head[N],ecnt,pre[N],Nxt[N],a[N],ans;
bool vis[N],t[N];
void add(int bg,int ed) {nxt[++ecnt]=head[bg];to[ecnt]=ed;head[bg]=ecnt;}
void del(int x) {
int p=pre[x];
Nxt[p]=Nxt[x];
pre[Nxt[x]]=p;
}
void bfs(int x) {
queue<int>q;
q.push(x);
while(!q.empty()) {
a[ans]++;
int u=q.front();q.pop();
for(int i=head[u];i;i=nxt[i]) {
t[to[i]]=1;
}
for(int i=Nxt[0];i<=n;i=Nxt[i]) if(!t[i]) del(i),q.push(i);
for(int i=head[u];i;i=nxt[i]) {
t[to[i]]=0;
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1,aa,b;i<=m;i++) {
scanf("%d%d",&aa,&b);
add(aa,b);
add(b,aa);
}
for(int i=0;i<=n;i++) pre[i+1]=i,Nxt[i]=i+1;
for(int i=Nxt[0];i<=n;i=Nxt[0]) {
del(i);ans++;bfs(i);
}
cout<<ans<<endl;
sort(a+1,a+1+ans);
for(int i=1;i<=ans;i++) printf("%d ",a[i]);
return 0;
}