📜  门| GATE-CS-2017(套装1)|第 61 题(1)

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

门| GATE-CS-2017(套装1)|第 61 题

题目描述

给定一个二叉树,实现以下操作:

  • update(i, val):将第 i 个节点的值更新为 val
  • preSum(i):返回前 i 个节点的值的和,其中 i 是节点的编号。
示例
    1 ----> 2
   / \      / \
  3   4    5   6

bst = BST(6)
bst.update(4, 7) # 节点 4 的值更新为 7
bst.preSum(5) # 返回 15(节点 1 ~ 5 的和为 15)
思路

为了能够快速计算前 i 个节点的和,我们需要为每个节点维护一个前缀和,表示以这个节点为根的子树中所有节点的值的和。

对于每个节点,我们可以通过其父节点的前缀和和它自身的值计算出自身的前缀和,即:

prefixSum[node] = prefixSum[parent] + node.val

当调用 preSum(i) 时,我们只需要在树中从节点 i 开始向上遍历到根节点,累加节点的前缀和即可。

更新操作比较简单,只需要找到要更新的节点,更新其值并重新计算节点及其祖先节点的前缀和即可。

实现

我们可以定义一个节点类 Node,其中包含节点编号 index、节点值 val、左子节点 left、右子节点 right 和前缀和 prefixSum。然后定义一个二叉搜索树类 BST,其中包含树的大小 size 和根节点 root,以及以下方法:

  • __init__(self, n):初始化根节点为 None,大小为 n 的二叉搜索树。
  • _find(self, i):寻找节点编号为 i 的节点,如果不存在则返回 None。
  • update(self, i, val):将节点编号为 i 的节点的值更新为 val
  • _updatePrefixSum(self, node):递归更新节点 node 及其祖先节点的前缀和。
  • preSum(self, i):返回前 i 个节点的值的和。
代码
class Node:
    def __init__(self, index, val):
        self.index = index
        self.val = val
        self.left = None
        self.right = None
        self.prefixSum = val

class BST:
    def __init__(self, n):
        self.size = n
        self.root = None

    def _find(self, i):
        node = self.root
        while node:
            if i < node.index:
                node = node.left
            elif i > node.index:
                node = node.right
            else:
                return node
        return None

    def update(self, i, val):
        node = self._find(i)
        if node:
            delta = val - node.val
            node.val = val
            node.prefixSum += delta
            self._updatePrefixSum(node)

    def _updatePrefixSum(self, node):
        while node:
            node.prefixSum = node.val
            if node.left:
                node.prefixSum += node.left.prefixSum
            if node.right:
                node.prefixSum += node.right.prefixSum
            node = node.parent

    def preSum(self, i):
        node = self._find(i)
        prefixSum = 0
        while node:
            prefixSum += node.prefixSum
            node = node.parent
        return prefixSum