Files
teamnote/source/Graph/DominatorTree.cpp
2026-06-03 09:20:51 +09:00

52 lines
1.5 KiB
C++

// 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