1098: [POI2007]办公楼biu 链表+BFS

答案显然是补图的联通块的个数,然而N太大直接构造补图难以实现QAQ。
考虑到我们求的是联通块的个数,所以联通块内的点是没有必要都连边的,只要有一条边他就属于这个联通块,基于此,我们在找联通块时对于已经加入的点可以不必考虑,所以如果每次都O(n)的枚举是非常耗时间的,我们可以用链表的思想,如果一个点被删除了,就把它前后节点连接起来,之后就不会再经过这个节点,这样就将时间复杂度大大下降。
至于BFS还是DFS应该都可以吧QAQ,我写的BFS。
类似这样的或许还可以用UFS维护?

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,cnt,ans;
int a[100005],q[100005],head[100005],nxt[100005],pre[100005];
int next[4000005],list[4000005];
bool v[100005];
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}
inline void del(int x)
{
    nxt[pre[x]]=nxt[x];
    pre[nxt[x]]=pre[x];
}
inline void bfs(int i)
{
    int t=0,w=1,x;
    q[1]=i;
    while (t<w)
    {
        a[ans]++;
        x=q[++t];
        for (int i=head[x];i;i=next[i]) v[list[i]]=1;
        for (int i=nxt[0];i<=n;i=nxt[i]) 
            if (!v[i]) del(i),q[++w]=i;
        for (int i=head[x];i;i=next[i]) v[list[i]]=0;
    }
}
int main()
{
    n=read(); m=read();
    for (int i=1;i<=m;i++)
    {
        int u=read(),v=read();
        insert(u,v); insert(v,u);
    }
    for (int i=0;i<=n;i++) nxt[i]=i+1;
    for (int i=1;i<=n+1;i++) pre[i]=i-1;
    for (int i=nxt[0];i<=n;i=nxt[0])
        del(i),ans++,bfs(i);
    sort(a+1,a+ans+1);
    cout << ans << endl;
    for (int i=1;i<=ans;i++) printf("%d ",a[i]);
    return 0;
}

你可能感兴趣的:(1098: [POI2007]办公楼biu 链表+BFS)