Codechef 12.6 CLOSEST KDTree
Codechef 13.8 LYRC AC自动机

Codechef 15.5 GRAPHCNT Dominator Tree

shinbokuow posted @ Nov 25, 2015 11:16:09 AM in Something with tags Dominator Tree 图连通性 , 1232 阅读

 

题目大意:
给定一张$n$个点,$m$条边的有向图,问存在多少对点$(X,Y)$,使得存在两条从点1出发分别到$X$和$Y$的路径满足这两条路径只在点1处相交。
数据范围$1\leq{n}\leq{10^5},0\leq{m}\leq{5\times{10^5}}$。
算法讨论:
我们求出这张无向图以$1$为根的Dominator Tree,则点对$(X,Y)$合法当且仅当$X,Y$在Dominator Tree上的LCA为点1。
于是我们直接求出Dominator Tree,然后在树上进行简单的统计即可。
关于Dominator Tree的更多内容请参见李煜东的《图连通性若干拓展问题》。
时空复杂度:
时间复杂度$O(m\alpha(n,m))$,空间复杂度$O(m)$。
代码:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
int getc() {
    static const int L = 1 << 15;
    static char buf[L], *S = buf, *T = buf;
    if (S == T) {
        T = (S = buf) + fread(buf, 1, L, stdin);
        if (S == T)
            return EOF;
    }
    return *S++;
}
int getint() {
    static int c, x;
    while (!isdigit(c = getc()));
    x = c - '0';
    while (isdigit(c = getc()))
        x = (x << 1) + (x << 3) + c - '0';
    return x;
}
#define N 100010
#define M 500000
int n, m;
struct Graph {
    int head[N], nxt[M], to[M], ind;
    void addedge(int a, int b) {
        int q = ++ind;
        to[q] = b;
        nxt[q] = head[a];
        head[a] = q;
    }
}g, gr, tree;
int dfn[N], pa[N], id_p[N], id;
int sdom[N], idom[N], sroot[N], best[N];
void buildTree(int x) {
    //printf("%d\n", x);
    dfn[x] = ++id;
    id_p[id] = x;
    for (int j = g.head[x]; j; j = g.nxt[j]) {
        if (!dfn[g.to[j]]) {
            buildTree(g.to[j]);
            pa[dfn[g.to[j]]] = dfn[x];
        }
    }
}
int find(int x) {
    if (x == sroot[x])
        return x;
    int y = find(sroot[x]);
    if (sdom[best[x]] > sdom[best[sroot[x]]])
        best[x] = best[sroot[x]];
    return sroot[x] = y;
}
vector<int> sdom_son[N];
void LengauerTarjan() {
    int i, j, k, v;
    for (i = 1; i <= id; ++i)
        sroot[i] = sdom[i] = best[i] = i;
    for (i = id; i >= 2; --i) {
        for (j = gr.head[id_p[i]]; j; j = gr.nxt[j]) {
            if ((v = dfn[gr.to[j]])) {
                find(v);
                sdom[i] = min(sdom[i], sdom[best[v]]);
            }
        }
        sdom_son[sdom[i]].push_back(i);
        sroot[i] = pa[i];
        for (j = 0; j < sdom_son[pa[i]].size(); ++j) {
            find(v = sdom_son[pa[i]][j]);
            if (sdom[v] == sdom[best[v]])
                idom[v] = sdom[v];
            else
                idom[v] = best[v];
        }
        sdom_son[pa[i]].clear();
    }
    for (i = 2; i <= id; ++i) {
        if (idom[i] != sdom[i])
            idom[i] = idom[idom[i]];
        tree.addedge(id_p[idom[i]], id_p[i]);
    }
}
int siz[N];
void dfs(int x) {
    siz[x] = 1;
    for (int j = tree.head[x]; j; j = tree.nxt[j]) {
        dfs(tree.to[j]);
        siz[x] += siz[tree.to[j]];
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("tt.in", "r", stdin);
#endif
    n = getint();
    m = getint();
    int i, j, a, b;
    for (i = 1; i <= m; ++i) {
        a = getint();
        b = getint();
        g.addedge(a, b);
        gr.addedge(b, a);
    }
    
    buildTree(1);
    LengauerTarjan();
    
    dfs(1);
    
    long long ans = 0;
    for (j = tree.head[1]; j; j = tree.nxt[j])
        ans += (ll)siz[tree.to[j]] * (siz[1] - 1 - siz[tree.to[j]]);
    ans = ans / 2 + siz[1] - 1;
    cout << ans << endl;
    
    return 0;
}

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter