学习链接【学习笔记】支配树_cz_xuyixuan的博客-CSDN博客
主要的求法是最后两个结论:
定理4用来求sdom,先搞一个dfs树,然后将点按dfs序从大到小加入,对每个点维护到当前根(即已加入点)路径上sdom最小是哪个(sdom的比较是对dfs序比)记为home,可以用带权并查集完成。加入一个点,就先枚举所有能直接到达本身的相邻点,用他们的home更新我,然后加入我到dfs树父亲的边。
然后用推论1求idom,写一个倍增求(sdom[x], x]路径上sdom最小的点即可。
模板题 HDU4694 (建立根在n的支配树)
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define pii pair<int, int>
#define fi first
#define sc second
using namespace std;
const int inf = 1e9;
const int N = 2e6 + 100;
const ll mod = 998244353;void sol(int n, int m) {vector<vector<int>> adj(n + 1), radj(n + 1), tree_adj(n + 1);for (int i = 1; i <= m; i++) {int x, y;cin >> x >> y;adj[x].pb(y);radj[y].pb(x);}int tim = 0;vector<int> rnk(n + 1, 0), dfn(n + 1, 0), tree_fa(n + 1, 0);function<void(int)> dfs = [&](int x) {rnk[x] = ++tim, dfn[tim] = x;for (int y : adj[x]) {if (!rnk[y]) {tree_fa[y] = x;tree_adj[x].pb(y);dfs(y);}}};dfs(n);vector<int> sdom(n + 1, 0), rt(n + 1, 0), home(n + 1, 0);iota(all(sdom), 0);iota(all(rt), 0);iota(all(home), 0);function<int(int)> get_home = [&](int x) {if (rt[x] == x) {return home[x];}int tmp = get_home(rt[x]);if (rnk[sdom[tmp]] < rnk[sdom[home[x]]]) {home[x] = tmp;}rt[x] = rt[rt[x]];return home[x];};for (int i = n; i >= 1; i--) {int x = dfn[i];for (int y : radj[x]) {if (rnk[y] && rnk[sdom[get_home(y)]] < rnk[sdom[x]]) {sdom[x] = sdom[get_home(y)];}}rt[x] = tree_fa[x];}vector<int> dep(n + 1, 0);vector<vector<int>> jp(20, vector<int>(n + 1, 0)), mn(20, vector<int>(n + 1, 0));vector<int> idom(n + 1, 0);vector<ll> sum(n + 1, 0);function<void(int)> dfs_tree = [&](int x) {jp[0][x] = tree_fa[x];mn[0][x] = x;for (int j = 1; j < 20; j++) {jp[j][x] = jp[j - 1][jp[j - 1][x]];if (rnk[sdom[mn[j - 1][jp[j - 1][x]]]] < rnk[sdom[mn[j - 1][x]]]) {mn[j][x] = mn[j - 1][jp[j - 1][x]];} else {mn[j][x] = mn[j - 1][x];}}int dt = dep[x] - dep[sdom[x]];int ps = x, cur = x;for (int j = 19; j >= 0; j--) {if (dt >> j & 1) {if (rnk[sdom[mn[j][cur]]] < rnk[sdom[ps]]) {ps = mn[j][cur];}cur = jp[j][cur];} }if (sdom[ps] == sdom[x]) {idom[x] = sdom[x];} else {idom[x] = idom[ps];}sum[x] = sum[idom[x]] + x;for (int y : tree_adj[x]) {dep[y] = dep[x] + 1;dfs_tree(y);}};dfs_tree(n);for (int i = 1; i <= n; i++) {cout << sum[i] << " \n"[i == n];}
}signed main() {ios::sync_with_stdio(0);cin.tie(0);
// int tt;
// cin >> tt;
// while (tt--)int n, m;while (cin >> n >> m)sol(n, m);
}