BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset

BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset

Description

Input

输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。

Output

输出一行一个整数,表示该图的连通数。

Sample Input

3
010
001
100

Sample Output

9

HINT

对于100%的数据,N不超过2000。


 

直接缩点+拓扑排序统计答案即可。

每步转移是O(n)的,可以用bitset优化到O(n/32)。

其实就是想练习一下手写bitset,显然没有STL的块。

总时间复杂度O(nnm/32)

 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 2050
#define M 4000500
#define _min(x,y) ((x)<(y)?(x):(y))
typedef unsigned int ut;
const int M1=65535;
inline char nc() {
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rc() {
    char s=nc();
    while(s<'0'||s>'1') s=nc();
    return s=='1';
}
int rd() {
    int x=0; char s=nc();
    while(s<'0'||s>'9') s=nc();
    while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
    return x;
}
int n,block,h[1<<16];
int g1(unsigned int x) {
    return h[x>>16]+h[x&M1];
}
struct Bitset {
    ut b[70];
    int get_num() {
        int i,re=0;
        for(i=1;i<=block;i++) re+=g1(b[i]);
        return re;
    }
    Bitset operator | (const Bitset &x) const {
        Bitset re; int i;
        for(i=1;i<=block;i++) re.b[i]=(b[i]|x.b[i]);
        return re;
    }
}f1[N],f2[N];
int head[N],to[M],nxt[M],in[N],Q[N],l,r;
int S[N],bel[N],siz[N],L[80],R[80],pos1[N],pos2[N],dfn[N],low[N],tot,scc,top,ins[N],xx[M],yy[M],qwq,cnt;
inline void add(int u,int v) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void dfs(int x) {
    int i;
    dfn[x]=low[x]=++tot; S[++top]=x; ins[x]=1;
    for(i=head[x];i;i=nxt[i]) {
        if(!dfn[to[i]]) {
            dfs(to[i]);
            low[x]=_min(low[x],low[to[i]]);
        }else if(ins[to[i]]) {
            low[x]=_min(low[x],dfn[to[i]]);
        }
    }
    if(dfn[x]==low[x]) {
        int t=S[top--]; ins[t]=0;
        bel[t]=++scc; f2[scc]=f1[t];
        siz[scc]=1;
        while(t!=x) {
            t=S[top--]; ins[t]=0;
            bel[t]=scc; f2[scc]=f2[scc]|f1[t];
            siz[scc]++;
        }
    }
}
int main() {
    n=rd();
    register int i,j;
    int x;
    for(i=1;i<=M1;i++) h[i]=h[i>>1]+(i&1);
    block=n/32;
    for(i=1;i<=block;i++) {
        L[i]=R[i-1]+1; R[i]=i*32;
        for(j=L[i];j<=R[i];j++) {
            pos1[j]=i; pos2[j]=j-L[i];
        }
    }
    if(R[block]!=n) {
        L[block+1]=R[block]+1; R[++block]=n;
        for(i=L[block];i<=n;i++) pos1[i]=block,pos2[i]=i-L[block];
    }
    for(i=1;i<=n;i++) {
        for(j=1;j<=n;j++) {
            x=rc();
            if(x) f1[i].b[pos1[j]]|=(1<<pos2[j]),add(i,j),xx[++qwq]=j,yy[qwq]=i;
        }
        f1[i].b[pos1[i]]|=(1<<pos2[i]);
    }
    for(i=1;i<=n;i++) {
        if(!dfn[i]) dfs(i);
    }
    memset(head,0,sizeof(head)); cnt=0;
    for(i=1;i<=qwq;i++) {
        if(bel[xx[i]]!=bel[yy[i]]) {
            add(bel[xx[i]],bel[yy[i]]); in[bel[yy[i]]]++;
        }
    }
    for(i=1;i<=scc;i++) {
        if(!in[i]) Q[r++]=i;
    }
    int ans=0;
    while(l<r) {
        x=Q[l++]; ans+=siz[x]*f2[x].get_num();
        for(i=head[x];i;i=nxt[i]) {
            in[to[i]]--;
            f2[to[i]]=f2[to[i]]|f2[x];
            if(in[to[i]]==0) Q[r++]=to[i];
        }
    }
    printf("%d\n",ans);
}

 

posted @ 2018-06-28 11:20  fcwww  阅读(380)  评论(0编辑  收藏  举报