DFS序求LCA

DFS序求LCA

介绍

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

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

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

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

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

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

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

说明:x 的原因是因为 lcadfn 不一定在这个范围内。

还有一种不用记录 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 @   superl61  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示