【图论·强连通分量scc】hdu6072Logical Chain

来源:互联网 发布:手机淘宝设置在哪 编辑:程序博客网 时间:2024/05/22 16:39

非常有灵性的一道强连通分量。乍一看是道模板题,然而需要用bitset优化时间复杂度至1/64;bitset什么鬼啊喂,很佩服赛场上唯一做出来的大佬orz;

常规部分,学习了scc模板求强连通分量;
第一遍dfs给图上的倒序编号(最后访问到的标最小号);
第二遍在所有边反向后的图上dfs,从一个强连通分图上的点不可能访问到其他强分图上的点(为什么还没有理解)
cmp[I] = k 表示编号为i的点属于编号为k的强分图;
scc结束;

本题中节点数为t的强分图,对答案贡献t*(t-1)/2;

难点就是bitset 的理解和使用了(紧张);
首先试了下头文件#include
然而长度为8的bitset<8> b; 只能放8个0/1;
并不是很神奇;遂放弃,看大神的手写版;

这就非常有灵性了。
reset(int x) 好理解,初始化。x=0 b为0,x = 0xff,无限大;
flip(int x) 不好理解。8位,256个数,把x这个数0变1,1变0;
b[x>>5] 每一位表示32个数,x>>5确定x属于哪一位管;
将这一位加上2的x%32次方,表示这个数的存在

#define _CRT_SECURE_NO_WARNINGS#include<iostream>#include<cstdio>#include<vector>#include<cstring>#include<stack>#include<queue>#include<bitset>using namespace std;using std::bitset;typedef long long ll;const int maxv = 255;    struct BIT{        unsigned int b[8];        void reset(int x){ memset(b, x, sizeof(b)); }        void flip(int x){ b[x >> 5] ^= 1U << (x & 31); }        int get(int x){ return (b[x >> 5] >> (x & 31)) & 1; }    }G[maxv], rG[maxv], vis;int V;vector<int> vs;int cmp[maxv];int cnt = 0;inline int ctz(unsigned int s){    int x = 0;    while (!(s & 1))    {        ++x; s >>= 1;    }    return x;}void dfs(int v){    vis.flip(v);    unsigned int s;    for (int i = 0; i < 8; ++i){        while (1){             s = vis.b[i] & G[v].b[i];            if (!s) break;            //这里是什么原理依然没有搞清楚orz;            dfs((i << 5)| ctz(s));          }    }    vs.push_back(v);}void rdfs(int v){    ++cnt;    vis.flip(v);    unsigned int s;    for (int i = 0; i < 8; i++){        while (1){            s = vis.b[i] & rG[v].b[i];            if (!s) break;            rdfs((i << 5 )| ctz(s));        }    }}void scc(){    vis.reset(0xff);vs.clear();    for (int i = 0; i < V; i++){        if (vis.get(i)) dfs(i);    }    vis.reset(0xff);    ll ans = 0;    for (int i = vs.size() - 1; i >= 0; i--){        if (vis.get(vs[i])) {            cnt = 0;            rdfs(vs[i]);            ans += cnt*(cnt - 1) / 2;        }    }    printf("%lld\n", ans);}char c;int t, m;int main(){    scanf("%d", &t);    while (t--){        scanf("%d%d", &V, &m);        for (int i = 0; i <= V; i++){            G[i].reset(0);            rG[i].reset(0);        }        for (int i = 0; i < V; i++){            char g[maxv];            scanf("%s", g);            for (int j = 0; j < V; j++){                if (g[j] == '1') {                    G[i].flip(j);                    rG[j].flip(i);                }            }        }        while (m--){            int k; scanf("%d", &k);            for (int i = 1; i <= k; ++i){                int u, v;        scanf("%d%d", &u, &v);                G[u - 1].flip(v - 1);                rG[v - 1].flip(u - 1);            }            scc();        }    }}