太菜了…这都不会…
就是求反图的联通块。就是每次挑一个边在反图bfs出一个块。
我们每次找反图边扩展,是找原图中和当前节点不直接相连的其他点。直接暴力会变成 n2
所以需要把访问过的点马上删去。可以用链表。
这样每个点就只访问一次了。复杂度 O(n+m)
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005,maxe=4000005;
int n,m,ans[maxn];
int fir[maxn],nxt[maxe],son[maxe],tot;
void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
int vis[maxn],clk;
int L[maxn],R[maxn],tem[maxn];
void Del(int x){ R[L[x]]=R[x]; L[R[x]]=L[x]; }
queue<int> que;
void bfs(){
int x=R[0]; Del(x); que.push(x); ans[++ans[0]]=1;
while(!que.empty()){
int x=que.front(); que.pop(); clk++;
for(int j=fir[x];j;j=nxt[j]) vis[son[j]]=clk;
tem[0]=0;
for(int i=R[0];i!=n+1;i=R[i]) if(vis[i]!=clk){
que.push(i); tem[++tem[0]]=i; ans[ans[0]]++;
}
for(int i=1;i<=tem[0];i++) Del(tem[i]);
}
}
int main(){
freopen("bzoj1098.in","r",stdin);
freopen("bzoj1098.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y; scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
R[0]=1; for(int i=1;i<=n;i++) L[i]=i-1, R[i]=i+1; L[n+1]=n;
while(R[0]!=n+1) bfs();
sort(ans+1,ans+1+ans[0]);
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]);
return 0;
}