[POI2007]办公楼Biu

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;
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9808784.html