st表 LCA

我当时知道ST表可以 O(1) 求 LCA 的时候是极为震惊的,可以在需要反复使用 LCA 的时候卡常使用。

ST表!用于解决 RMQ问题

ST表

我可能写得不好,看专业的

怎么实现?

考虑把求 LCA 转换为 RMQ问题。我们对于树求一遍欧拉序,就是那个回溯也会记录的那个。我们处理出每个数第一次在欧拉序中出现的位置,欧拉序上每个位置的深度,以及欧拉序上每个位置出现的点的编号。这些信息都可以在一次 dfs 中求出。然后不难发现在回溯过程中加入的点是之前遍历的点的祖先,由此也不难推出结论。

在两个点在欧拉序上第一次出现的位置的区间中间的深度最小的点就是这两个点的 LCA

那么直接变成 RMQ问题,上 ST表。

Code:

int idx;
int dfn[N + 3], app[2 * N + 3], dep2[2 * N + 3];
int dep[N + 3];
void dfs1(int u, int f, int deep){
	dfn[u] = ++idx;
	app[idx] = u;
	dep[u] = deep;
	dep2[idx] = deep;
	for(int i = head[u]; ~i; i = nxt[i]){
		int v = to[i];
		if(v == f) continue;
		dfs1(v, u, deep + 1);
		app[++idx] = u;
		dep2[idx] = deep;
	}
}
int lg2[2 * N + 3];
int st[N * 2 + 3][LG + 4];
void init_ST(){
	for(int i = 1; i <= (n << 1); ++i){
		st[i][0] = i;
	}
	lg2[1]=0;
	for(int i = 2; i <= (n << 1); ++i){
		lg2[i] = lg2[i >> 1] + 1;
	}
	for(int j = 1; (1 << j) <= (n << 1); ++j){
		for(int i = 1; i + (1 << j) - 1 <= (n << 1); ++i){
			int a = st[i][j - 1], b = st[i + (1 << (j - 1) )][j - 1];
			if(dep2[a] < dep2[b]) st[i][j] = a;
			else st[i][j] = b;
		}
	}
}
int LCA(int a,int b){
	int l = dfn[a], r = dfn[b];
	if(l > r) std::swap(l, r);
	int s = lg2[r - l + 1];
	int x = st[l][s], y = st[r - (1 << s) + 1][s];
	return dep2[x] < dep2[y] ? app[x] : app[y];
}
int dist(int x, int y){
	return dep[x] + dep[y] - 2 * dep[LCA(x, y)];
}
posted @   cbdsopa  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示