学习链接【学习笔记】支配树_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);
}