📅  最后修改于: 2023-12-03 15:36:20.703000             🧑  作者: Mango
本次介绍的主题是在一颗树中,从距离给定节点X最多D个距离的子树中查找最小权重的查询。
这种查询在实际开发中十分常见,比如在社交网络中基于距离进行推荐,或者在地理信息系统中通过位置坐标查找周围最近的设施等。
常规的做法是进行树上的 DFS,找出所有距离节点X最多D个距离的节点,然后再从这些节点中找到权重最小的节点。这个过程可能比较费时,时间复杂度较高。
一种优化的方法是使用树上的 LCA(最近公共祖先)算法。通过预处理出 LCA 表,可以快速地在两个节点间查询其最近的公共祖先,从而计算出它们之间的距离。利用这一点,我们可以在 O(logN) 的时间复杂度下找到距离节点 X 最多 D 个距离的所有节点。
实现此查询的伪代码如下:
query(x, d):
ans = INF
for each node in subtree[x] do
if distance(x, node) <= d then
ans = min(ans, weight[node])
return ans
其中,subtree[x]
表示以节点 x
为根的子树,distance(x, node)
表示节点 x
和节点 node
之间的距离,weight[node]
表示节点 node
的权重。
为了加快查询速度,可以使用 LCA 算法的预处理表。预处理的过程可以使用 Tarjan 算法或倍增算法,时间复杂度为 O(NlogN)。
代码示例:
# 用邻接表构建树
n = int(input())
adj = [[] for _ in range(n)]
for i in range(n - 1):
u, v = map(int, input().split())
adj[u-1].append(v-1)
adj[v-1].append(u-1)
# 节点的权重和距离
weight = [0] * n
distance = [0] * n
# 计算 LCA 表
parent = [[-1] * n for _ in range(n)]
depth = [0] * n
def dfs(u, p, d):
parent[u][0] = p
depth[u] = d
for v in adj[u]:
if v != p:
dfs(v, u, d + 1)
def calc_lca(u, v):
if depth[u] < depth[v]:
u, v = v, u
diff = depth[u] - depth[v]
for i in range(20):
if (diff >> i) & 1:
u = parent[u][i]
if u == v:
return u
for i in range(20, -1, -1):
if parent[u][i] != parent[v][i]:
u = parent[u][i]
v = parent[v][i]
return parent[u][0]
dfs(0, -1, 0)
for k in range(1, 20):
for i in range(n):
if parent[i][k-1] != -1:
parent[i][k] = parent[parent[i][k-1]][k-1]
# 查询函数
def query(x, d):
ans = float('inf')
for u in range(n):
if distance[u] <= d and calc_lca(x, u) == x:
ans = min(ans, weight[u])
return ans
# 输入节点的权重和距离
for i in range(n):
weight[i], distance[i] = map(int, input().split())
# 示例查询
x, d = 0, 2
print(query(x, d))
返回的代码片段:
query(x, d):
ans = INF
for each node in subtree[x] do
if distance(x, node) <= d then
ans = min(ans, weight[node])
return ans