• 模板汇总——Tarjian


    1. 单向边  + 新图建边

    int belong[N], dfn[N], low[N], now_time, scc_cnt;
    stack<int> s;
    void dfs(int u){
        dfn[u] = low[u] = ++now_time;
        s.push(u);
        for(int i = head[u]; ~i; i = nt[i]){
            if(!dfn[to[i]]) dfs(to[i]);
            if(!belong[to[i]]) low[u] = min(low[u], low[to[i]]);
        }
        if(dfn[u] == low[u]){
            ++scc_cnt;
            int now;
            while(1){
                now = s.top(); s.pop();
                belong[now] = scc_cnt;
                if(now == u) break;
            }
        }
    }
    void scc(int n){
        now_time = scc_cnt = 0;
        for(int i = 1; i <= n; ++i)
            if(!belong[i]) dfs(i);
        int v;
        for(int i = 1; i <= n; ++i){
            for(int j = head[i]; ~j; j=nt[j]){
                v = to[j];
                if(belong[v] != belong[i]){
                        vc[belong[i]].pb(belong[v]);
                }
            }
        }
    }
    View Code

    2.双向边 + 新图建边

    int belong[N], dfn[N], low[N], now_time, scc_cnt;
    vector<int> vc[N];
    vector<pll> e[N];
    stack<int> s;
    void dfs(int u, int id){
        dfn[u] = low[u] = ++now_time;
        s.push(u);
        for(int i = head[u]; ~i; i = nt[i]){
            if(i == (id^1)) continue;
            if(!dfn[to[i]]) dfs(to[i], i);
            if(!belong[to[i]]) low[u] = min(low[u], low[to[i]]);
        }
        if(dfn[u] == low[u]){
            ++scc_cnt;
            int now;
            while(1){
                now = s.top(); s.pop();
                belong[now] = scc_cnt;
                if(now == u) break;
            }
        }
    }
    void scc(int n){
        for(int i = 1; i <= n; ++i) dfn[i] = low[i] = belong[i] = 0;
        while(!s.empty()) s.pop();
        now_time = scc_cnt = 0;
        for(int i = 1; i <= n; ++i)
            if(!belong[i]) dfs(i, -1);
        for(int i = 0, u, v; i < tot; i += 2){
            u = to[i], v = to[i+1];
            u = belong[u], v = belong[v];
            if(u != v) e[u].pb(pll(v,i/2+1)), e[v].pb(pll(u,i/2+1));
        }
    }
    View Code

    3.边双连通分量。

      边双连通就是没有一个桥。

      桥的定义就是断开这个边能使得图分为2部分。

      先找到桥, 然后再dfs不经过桥所能到达的点都是同一个边双联通分量。  

    int dfn[N], low[N], dtot;
    void Tarjan(int o, int u){
        dfn[u]= low[u] = ++dtot;
        for(int i = head[u]; ~i; i = nt[i]){
            int v = to[i];
            if(!dfn[v]){
                Tarjan(u, v);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u])
                    bridge[i] = bridge[i^1] = 1;
            }
            else if(v != o)
                low[u] = min(low[u], dfn[v]);
        }
    }
    int c[N], dcc;
    void dfs(int u){
        c[u] = dcc;
        for(int i = head[u]; i; i = nt[i]){
            int v = to[i];
            if(c[v] || bridge[i]) continue;
            dfs(v);
        }
    }
    int ok[N];
    vector<pll> vc[N];
    void e_dcc(){
        for(int i = 1; i <= n; ++i)
            if(!dfn[i]) Tarjan(0, i);
        for(int i = 1; i <= n; ++i)
            if(!c[i]) {
                ++dcc;
                dfs(i);
            }
        for(int i = 0; i <= tot; i += 2){
            int u = to[i^1], v = to[i];
            u = c[u], v = c[v];
            if(u == v){
                ok[u] |= val[i];
            }
            else {
                vc[u].pb({v,val[i]});
                vc[v].pb({u,val[i]});
            }
        }
    }
    View Code
  • 相关阅读:
    「NOIP2011」聪明的质监员
    「CF5E」Bindian Signalizing
    「NOIP2017」列队
    「NOIP2016」愤怒的小鸟
    「牛客CSP-S2019赛前集训营2」服务器需求
    「牛客CSP-S2019赛前集训营1」仓鼠的石子游戏
    「SCOI2010」幸运数字
    函数求值一<找规律>
    梯形
    F(k)<(维护+枚举)(找规律+递推+枚举)>
  • 原文地址:https://www.cnblogs.com/MingSD/p/10097365.html
Copyright © 2020-2023  润新知