📌  相关文章
📜  从距离节点X最多D个距离节点的子树中查找最小权重的查询(1)

📅  最后修改于: 2023-12-03 15:36:20.703000             🧑  作者: Mango

从距离节点X最多D个距离节点的子树中查找最小权重的查询

本次介绍的主题是在一颗树中,从距离给定节点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