#include<bits/stdc++.h>
using namespace std;
struct Dominators {
const int inf = 0x3f3f3f3f;
bool isBuild, isCalcDfn, isCalcSiz; // 保证不重复操作的变量
int n, tim, parTim, S;
vector<int> fath, fa, sdom, idom, mn, dfn, pos, siz, firDfn, secDfn;
vector<vector<int>> orignEdge, rOrignEdge, semiEdge, idomEdge;
Dominators(int n, int S) : n(n), S(S),
fath(n + 1), fa(n + 1), sdom(n + 1), idom(n + 1), mn(n + 1), dfn(n + 1), pos(n + 1),
orignEdge(n + 1), rOrignEdge(n + 1), semiEdge(n + 1), idomEdge(n + 1) {
iota(fa.begin(), fa.end(), 0);
iota(sdom.begin(), sdom.end(), 0);
iota(mn.begin(), mn.end(), 0);
isCalcSiz = isCalcDfn = isBuild = parTim = tim = 0;
}
// 添加正图边和反图边
void addGraphEdge(int u, int v) {
orignEdge[u].push_back(v);
rOrignEdge[v].push_back(u);
}
// 添加半支配树树边
void addSemiEdge(int u, int v) {
semiEdge[u].push_back(v);
}
// 添加支配树树边
void addIdomEdge(int u, int v) {
idomEdge[u].push_back(v);
}
void tarjan(int u) {
dfn[u] = ++tim; pos[tim] = u;
for(int v : orignEdge[u]) {
if(!dfn[v]) {
fath[v] = u;
tarjan(v);
}
}
}
int find(int x) {
if(fa[x] == x) return fa[x];
int rt = find(fa[x]);
if(dfn[sdom[mn[fa[x]]]] < dfn[sdom[mn[x]]]) mn[x] = mn[fa[x]];
return fa[x] = rt;
}
// 使用该函数得到直接支配点
void dominate() {
tarjan(S);
for(int ii = tim; ii >= 2; ii--) {
int u = pos[ii], res = inf;
for(int v : rOrignEdge[u]) {
if(!dfn[v]) continue;
if(dfn[v] < dfn[u]) {
res = min(res, dfn[v]);
} else {
find(v);
res = min(res, dfn[sdom[mn[v]]]);
}
}
sdom[u] = pos[res];
fa[u] = fath[u];
addSemiEdge(sdom[u], u);
for(int v : semiEdge[u = fath[u]]) {
find(v);
if(u == sdom[mn[v]]) {
idom[v] = u;
} else {
idom[v] = mn[v];
}
}
semiEdge[u].clear();
}
for(int i = 2; i <= tim; i++) {
int u = pos[i];
if(sdom[u] ^ idom[u]) idom[u] = idom[idom[u]];
}
}
void dfsSiz(int u) {
siz[u] = 1;
for(int v : idomEdge[u]) {
dfsSiz(v);
siz[u] += siz[v];
}
}
void dfsDfn(int u) {
firDfn[u] = ++parTim;
for(int v : idomEdge[u]) {
dfsDfn(v);
}
secDfn[u] = ++parTim;
}
// 构建支配树
void buildIdomTree() {
if(isBuild) return ; isBuild = 1;
for(int i = 1; i <= n; i++) if(idom[i]) {
addIdomEdge(idom[i], i);
}
}
// 求每个点可支配的点
void calcSiz() {
if(isCalcSiz) return ; isCalcSiz = 1;
siz = vector<int> (n + 1);
buildIdomTree();
dfsSiz(S);
}
void calcDfn() {
if(isCalcDfn) return ; isCalcDfn = 1;
firDfn = vector<int> (n + 1);
secDfn = vector<int> (n + 1);
dfsDfn(S);
}
// 判断在支配树上x是不是为y的祖先
bool isAncestor(int x, int y) {
buildIdomTree();
calcDfn();
return firDfn[x] < firDfn[y] && firDfn[y] < secDfn[x];
}
// 打印每个点的直接支配点
void printIdom() {
for(int i = 1; i <= n; i++) {
cout << i << " " << idom[i] << "\n";
}
}
};