支配树模板,支持计算支配树子树大小,判断两个点在支配树上的祖先关系
#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"; } } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】