📌  相关文章
📜  使用LCA查询以找到给定树中两个节点之间的最大和最小权重。(1)

📅  最后修改于: 2023-12-03 14:49:48.918000             🧑  作者: Mango

使用LCA查询以找到给定树中两个节点之间的最大和最小权重。

简介

LCA是指最近公共祖先,是指在一棵树上,求两个节点的最近公共祖先节点的问题。LCA问题是树上询问问题的经典问题之一,现在我们考虑利用LCA查询树中两个节点之间的最大和最小权重。

算法原理

对于一棵树,我们可以用树链剖分算法将它分成若干链,然后在每条链中查找两个节点之间的最大和最小权重。这就是LCA查询树中两个节点之间的最大和最小权重的基本思路。

具体来说,在每条链上,我们可以使用线段树对节点进行区间查询。对于每个节点,我们可以记录它到根节点的距离,这样我们就可以快速定位每个节点在链上的位置。

然后,我们可以使用LCA算法找到两个节点的最近公共祖先。根据最近公共祖先的性质,它一定是两个节点在树上的路径上最深的公共节点。因此,我们可以将查询转化为两个节点到最近公共祖先的路径上的权重最大或最小值问题。

由于我们已经将树链剖分为链,而相邻的链之间最多只有一个公共节点(即一个节点的父亲节点),因此我们只需要在公共节点处处理一下即可。在处理到公共节点时,我们只需要将两个节点到公共节点路径上的线段树合并一下即可。

代码示例

下面是一个实现了LCA查询最大权重的代码片段。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
        self.max_val = -float('inf')

class Solution:
    def max_weight(self, root: TreeNode, p: TreeNode, q: TreeNode) -> int:
        # Step 1: 构建 dfs 序
        dfs_seq = []
        index = {}
        stack = [root]
        while stack:
            node = stack.pop()
            dfs_seq.append(node)
            index[node] = len(dfs_seq) - 1
            if node.left:
                stack.append(node.left)
            if node.right:
                stack.append(node.right)

        # Step 2: 构建 ST 表
        n = len(dfs_seq)
        st_len = 2 ** (n - 1).bit_length()
        st = [None] * (2 * st_len - 1)
        def build_st(i, l, r):
            if l == r:
                st[i] = dfs_seq[l]
            else:
                m = (l + r) // 2
                build_st(2 * i + 1, l, m)
                build_st(2 * i + 2, m + 1, r)
                st[i] = st[2 * i + 1] if index[st[2 * i + 1]] < index[st[2 * i + 2]] else st[2 * i + 2]
        
        build_st(0, 0, n - 1)

        # Step 3: 计算 dfs 序中每个节点的到根节点的距离
        height = {root: 0}
        def calc_height(node):
            if node.left:
                height[node.left] = height[node] + 1
                calc_height(node.left)
            if node.right:
                height[node.right] = height[node] + 1
                calc_height(node.right)
        calc_height(root)

        # Step 4: 在 LCA 上计算最大值
        def update_max(node):
            if node is None:
                return -float('inf')

            if node is p or node is q:
                return node.val
            
            left = update_max(node.left)
            right = update_max(node.right)
            node.max_val = max(node.val, left, right)
            return node.max_val

        lca = self.find_lca(root, p, q)
        update_max(lca)

        # Step 5: 在 LCA 上查找最大值
        max_val = -float('inf')
        node = p
        while node is not lca:
            max_val = max(max_val, node.max_val)
            node = node.left if node.left is not None else node.right
        
        node = q
        while node is not lca:
            max_val = max(max_val, node.max_val)
            node = node.left if node.left is not None else node.right

        return max_val

    # LCA 的实现
    def find_lca(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        if root is None:
            return None

        if root.val == p.val or root.val == q.val:
            return root

        left = self.find_lca(root.left, p, q)
        right = self.find_lca(root.right, p, q)

        if left is not None and right is not None:
            return root

        return left if left is not None else right

上面是使用Python实现的LCA求最大权重的程序示例,其中我们使用了dfs序、线段树等数据结构。对于求最小权重,只需要把update_max函数改为计算最小值即可。

总结

LCA查询树中两个节点之间的最大和最小权重是树上查询问题中的一种经典问题,它的实现需要结合LCA、树链剖分、线段树以及其它数据结构和算法。这种算法涉及到的知识和技巧很多,但是掌握了它,将可以在树上进行各种复杂的查询和操作。