// https://ideone.com/aO6cH4
namespace dtree{  // by cki86201
vector<int> E[N], RE[N], rdom[N];
int S[N], RS[N], cs;
int par[N], val[N], sdom[N], rp[N], dom[N];
void clear(int n) { cs = 0;
    for(int i=0;i<=n;i++) {
        par[i] = val[i] = sdom[i] = rp[i] = dom[i] = S[i] = RS[i] = 0;
        E[i].clear(); RE[i].clear(); rdom[i].clear();
    }
}
void add_edge(int x, int y) { E[x].push_back(y); }
void Union(int x, int y) { par[x] = y; }
int Find(int x, int c = 0) {
    if(par[x] == x) return c ? -1 : x;
    int p = Find(par[x], 1);
    if(p == -1) return c ? par[x] : val[x];
    if(sdom[val[x]] > sdom[val[par[x]]]) val[x] = val[par[x]];
    par[x] = p;
    return c ? p : val[x];
}
void dfs(int x) {
    RS[ S[x] = ++cs ] = x;
    par[cs] = sdom[cs] = val[cs] = cs;
    for(int e : E[x]) {
        if(S[e] == 0) dfs(e), rp[S[e]] = S[x];
        RE[S[e]].push_back(S[x]);
    }
}
int solve(int s, int *up) { // Calculate idoms
    dfs(s);
    for(int i=cs;i;i--) {
        for(int e : RE[i]) sdom[i] = min(sdom[i], sdom[Find(e)]);
        if(i > 1) rdom[sdom[i]].push_back(i);
        for(int e : rdom[i]) {
            int p = Find(e);
            if(sdom[p] == i) dom[e] = i;
            else dom[e] = p;
        }
        if(i > 1) Union(i, rp[i]);
    }
    for(int i=2;i<=cs;i++) if(sdom[i] != dom[i]) dom[i] = dom[dom[i]];
    for(int i=2;i<=cs;i++) up[RS[i]] = RS[dom[i]];
    return cs;
}
} // namespace dtree

int par[N];
dtree::add_edge(a, b); // a -> b
int cnt = dtree::solve(s, par);
// cnt : s에서 도달할 수 있는 정점, par: dominator tree의 par
