DFS序求LCA

DFS序求LCA

介绍

欧拉序求LCA 的数组总是会忘记开两倍,并且预处理的常数较大。用 DFS序求LCA 可以解决这些问题。

欧拉序:进节点和出节点会重复记录节点。

DFS序:深度优先搜索的顺序,不会重新记录。

假设要求 \(lca(u,v)\), 且 \(dfn[u] < dfn[v]\)

那么 \(dfn[u] \sim dfn[v]\) 的所有点都在 \(lca(u,v)\) 子树中。

其中包括 \(lca\)\(v\) 方向上的第一个点 \(x\), 显然这个点是 \(dfn[u] \sim dfn[v]\)\(dep\) 最小的,和 欧拉序求LCA 一样, 我们用 st表 找到这个位置就可以,min函数改为 比较dep。

这样就找到了 \(x\), 那么 \(lca(u,v) = fa[x]\)

说明:\(x\) 的原因是因为 \(lca\)\(dfn\) 不一定在这个范围内。

还有一种不用记录 \(dep\) 仅依靠 \(dfn\) 求解 lca 的小技巧:\(dfn\) 改为记录每个点的父节点, 最终 st表求出的值就是 lca。(详情见参考博客)

\(dfn[u] + 1\) 的原因是考虑到了 \(u, v\) 在同一条链上的情况。

【模板】最近公共祖先(LCA)

struct LCA{
	struct node{
		int v, ne;
	}e[N << 1];
	int first[N], idx = 0;
	int dep[N], fa[N], dfn[N], rev[22][N], cnt = 0;
	void add(int x, int y){
		e[++ idx] = (node){y, first[x]};
		first[x] = idx;
	}
	void dfs(int u, int f){
		fa[u] = f;
		dep[u] = dep[f] + 1;
		dfn[u] = ++ cnt;
		rev[0][cnt] = u;
		for(int i = first[u]; i; i = e[i].ne){
			int v = e[i].v;
			if(v == f) continue;
			dfs(v, u);
		}
	}
	int cmin(int x, int y){
		if(dep[x] < dep[y]) return x;
		return y;
	}
	int getlca(int x, int y){
		if(x == y) return x;
		if((x = dfn[x]) > (y = dfn[y])) swap(x, y);
		int t = __lg(y - x++);
		return fa[cmin(rev[t][x], rev[t][y - (1 << t) + 1])];
	}
	void init(){
		dfs(root, 0);
		F(j, 1, 20) F(i, 1 , n - (1 << j) + 1) rev[j][i] = cmin(rev[j - 1][i], rev[j - 1][i + (1 << (j - 1))]);
	}
}lca;

参考博客

冷门科技 —— DFS 序求 LCA - By Alex_Wei

posted @ 2024-09-24 19:11  superl61  阅读(220)  评论(0)    收藏  举报