[POI2007]辦公樓Biu
阿新 • • 發佈:2018-11-11
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; }