"""
https://www.lanqiao.cn/problems/4385/learning/?page=1&first_category_id=1&name=%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88
"""
import sys
sys.setrecursionlimit(10000)
input = sys.stdin.readline
# 预处理deep数组和p数组
def dfs(u, fa):
deep[u] = deep[fa] + 1
p[u][0] = fa
for i in range(1, 21):
# 节点u往上走2^i步 = 节点u网上走2^(i-1)步所在的节点往上走2^(i-1)步
p[u][i] = p[p[u][i - 1]][i - 1]
for v in G[u]:
if v == fa: continue
dfs(v, u)
def lca(x, y):
# 保证x更深
if deep[x] < deep[y]:
x, y = y, x
# x利用倍增的方法往上走, 使得deep[x] == deep[y]
# i 从大往小枚举 走2^i步
# 如果走2^i到达的点p[x][i]的深度仍大于deep[y]则可以走
for i in range(20, -1, -1):
if deep[p[x][i]] >= deep[y]:
x = p[x][i]
# 此时deep[x] == deep[y]
if x == y:
return x
# 一起往上走, 如果走2^i步, 两个点的公共祖先相同则不可以走, 否则可以走,
# 因为i从大往小, 走2^i步肯定是它们的公共祖先, 但不是最近的, 所以需要
# 不断走, 让x和y走到最近公共祖先下的两个儿子节点, 然后再走一步即是最近
# 公共祖先
for i in range(20, -1, -1):
if p[x][i] != p[y][i]:
x, y = p[x][i], p[y][i]
return p[x][0]
n = int(input())
G = [[] for i in range(n + 1)]
# deep[u]表示节点u的深度
deep = [0] * (n + 1)
# p[u][i]表示节点u往上走2^i到达的节点,
# 初始值默认都是到达根节点, 因为根节点深度最小为0, 走2^i步后没有该节点也不影响结果
p = [[0] * 21 for i in range(n + 1)]
# 邻接表存图
for _ in range(n - 1):
u, v = map(int, input().split())
G[u].append(v)
G[v].append(u)
dfs(1, 0)
Q = int(input())
for _ in range(Q):
x, y = map(int, input().split())
print(lca(x, y))
蓝桥杯-最近公共祖先
于 2024-04-01 22:09:43 首次发布
文章讲述了如何在给定的树形结构图中,利用深度优先搜索和最近公共祖先(LCA)算法来找出任意两点间的最近公共祖先。通过构建深度数组和路径压缩数组,有效地解决了图论中的查询问题。
摘要由CSDN通过智能技术生成