支配树学习笔记

学习链接【学习笔记】支配树_cz_xuyixuan的博客-CSDN博客

主要的求法是最后两个结论:

支配树学习笔记_第1张图片

定理4用来求sdom,先搞一个dfs树,然后将点按dfs序从大到小加入,对每个点维护到当前根(即已加入点)路径上sdom最小是哪个(sdom的比较是对dfs序比)记为home,可以用带权并查集完成。加入一个点,就先枚举所有能直接到达本身的相邻点,用他们的home更新我,然后加入我到dfs树父亲的边。

然后用推论1求idom,写一个倍增求(sdom[x], x]路径上sdom最小的点即可。

模板题 HDU4694 (建立根在n的支配树)

#include
#define ll long long
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define pii pair
#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> 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 rnk(n + 1, 0), dfn(n + 1, 0), tree_fa(n + 1, 0);
	function 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 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 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 dep(n + 1, 0);
	vector> jp(20, vector(n + 1, 0)), mn(20, vector(n + 1, 0));
	vector idom(n + 1, 0);
	vector sum(n + 1, 0);
	function 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);
}

你可能感兴趣的:(学习,笔记)