Bzoj1098[POI2007]办公楼biu
求补图的联通块个数。
补图非常大。
链表维护搜索。
把所有点加到链表中,每次取出链头,删掉,联通块个数++;扔进队列,取出队首,把原图跟他有连边的标记了,遍历一遍链表把没有标记的删除,入队,继续取出队首重复。
RE了半个下午发现建图边开小了。。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=100007;
const int M=2000007;
typedef long long LL;
using namespace std;
int n,m,o,head,tail,r[N],l[N],tot,sz[N],vis[N];
queue<int>que;
template<typename T> void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int ecnt,fir[N],nxt[M<<1],to[M<<1];
void add(int u,int v) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}
int main() {
#ifdef DEBUG
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
read(n); read(m);
for(int i=1;i<=m;i++) {
int u,v;
read(u); read(v);
add(u,v);
}
head=0; tail=n+1;
r[head]=1;
for(int i=1;i<=n;i++) {
r[i]=i+1;
l[i]=i-1;
}
l[tail]=n;
while(r[head]!=tail) {
tot++;
int x=r[head];
l[r[x]]=l[x];
r[l[x]]=r[x];
que.push(x);
sz[tot]++;
while(!que.empty()) {
int x=que.front();
que.pop();
for(int i=fir[x];i;i=nxt[i]) {
int y=to[i];
vis[y]=x;
}
for(int i=r[head];i!=tail;i=r[i]) {
if(vis[i]!=x) {
sz[tot]++;
que.push(i);
l[r[i]]=l[i];
r[l[i]]=r[i];
}
}
}
}
sort(sz+1,sz+tot+1);
printf("%d\n",tot);
for(int i=1;i<=tot;i++) printf("%d ",sz[i]);
puts("");
return 0;
}