bzoj 2208: [Jsoi2010]连通数

神奇bitset;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=(n);i++)
using namespace std;
const int N = 2005;
const int M = 4000000;
struct E {
    int to, next;
    E(int to = 0, int next = 0): to(to), next(next) {}
} edge[2][M];
int head[2][N], tot[2], n;
void add(int x, int y, int op) {
    edge[op][++tot[op]] = E(y, head[op][x]);
    head[op][x] = tot[op];
}
int pre[N], scc[N], scc_cnt = 0, fa[N], lw[N], clk = 0, sta[N], top = 0, num[N], vis[N];
void dfs(int x) {
    pre[x] = lw[x] = ++clk;
    sta[++top] = x;

    for(int i = head[0][x]; i; i = edge[0][i].next)if(!scc[edge[0][i].to]) {
            int v = edge[0][i].to;

            if(!pre[v]) {
                dfs(v);
                lw[x] = min(lw[x], lw[v]);
            } else if(pre[v] < lw[x])lw[x] = pre[v];

        }

    if(lw[x] == pre[x]) {
        scc_cnt++;

        while(top) {
            scc[sta[top]] = scc_cnt;
            num[scc_cnt]++;

            if(sta[top--] == x)break;
        }
    }
}
void dfs2(int x) {
    vis[x] = 1;

    for(int i = head[1][x]; i; i = edge[1][i].next) {
        int v = edge[1][i].to;

        if(!vis[v])
            dfs2(v);
    }
    sta[top--] = x;
}
bitset<N> t[N];
int main() {
//    freopen("in.in", "r", stdin);
//    freopen("out.out","w",stdout);
    scanf("%d", &n);
    char s[N];
    tot[0] = tot[1] = 0;
    rep(i, 1, n) {
        scanf("%s", s + 1);

        rep(j, 1, n)if(s[j] == '1')add(i, j, 0);
    }
    rep(i, 1, n)

    if(!pre[i])
    dfs(i);

    rep(x, 1, n){t[scc[x]][x] = 1;
    for(int i = head[0][x]; i; i = edge[0][i].next) {

        int v = edge[0][i].to;

        if(scc[x] != scc[v])add(scc[x], scc[v], 1);
    }
    }

    top = scc_cnt;

    rep(i, 1, scc_cnt)if(!vis[i])
        dfs2(i);

    int ans = 0;
//rep(x,1,n){printf("%d\n",x);rep(i,0,n+1)printf("%d",t[x][i] ? 1 : 0);printf("\n");}
    for(int x = scc_cnt; x; x--) {
        for(int i = head[1][sta[x]]; i; i = edge[1][i].next) {
            int v = edge[1][i].to;
            t[sta[x]] =t[sta[x]] | t[v];
        }
//printf("%d\n",sta[x]);rep(i,1,n)printf("%d",t[sta[x]][i] ? 1 : 0);printf("\n");
        ans += num[sta[x]] * t[sta[x]].count();
    }

    printf("%d", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值