📜  间隔总和和除数更新(1)

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

间隔总和和除数更新

在编程中,我们可能会需要多次求解一个区间内所有数的和,或者更新这个区间内的除数,这时候我们可以通过预处理来解决这个问题。下面将介绍两种常见的预处理方法。

1. 前缀和

前缀和的思想是将原序列前缀的和进行预处理,然后可以在 O(1) 的时间内求得任意区间内的和。

def prefix_sum(nums):
    n = len(nums)
    prefix_sum = [0] * (n + 1)  # 注意下标从1开始
    for i in range(1, n+1):
        prefix_sum[i] = prefix_sum[i-1] + nums[i-1]
    return prefix_sum

def sum_range(prefix_sum, left, right):
    return prefix_sum[right+1] - prefix_sum[left]

该方法的时间复杂度是 $O(n)$,只需要一次预处理和O(1)的查询即可。

2. 线段树

线段树是一种二叉树结构,其每个节点表示一个区间。该结构可以较快地解决区间查询和区间更新问题。

class SegmentTree:
    def __init__(self, nums):
        self.n = len(nums)
        self.tree = [0] * (self.n * 4)  # 定义4倍空间的线段树数组
        self.build(1, 0, self.n-1, nums)

    def build(self, node, start, end, nums):
        if start == end:
            self.tree[node] = nums[start]
        else:
            mid = (start + end) // 2
            left = 2 * node
            right = 2 * node + 1
            self.build(left, start, mid, nums)
            self.build(right, mid+1, end, nums)
            self.tree[node] = self.tree[left] + self.tree[right]

    def sum_range(self, node, start, end, left, right):
        if left <= start and end <= right:
            return self.tree[node]
        if right < start or end < left:
            return 0
        mid = (start + end) // 2
        left_node = 2 * node
        right_node = 2 * node + 1
        return self.sum_range(left_node, start, mid, left, right) + \
               self.sum_range(right_node, mid+1, end, left, right)

    def update(self, node, start, end, index, value):
        if start == end:
            self.tree[node] = value
        else:
            mid = (start + end) // 2
            left_node = 2 * node
            right_node = 2 * node + 1
            if index <= mid:
                self.update(left_node, start, mid, index, value)
            else:
                self.update(right_node, mid+1, end, index, value)
            self.tree[node] = self.tree[left_node] + self.tree[right_node]

该方法的时间复杂度为 $O(log_2 n)$,需要一次预处理和O(logn)的查询和更新操作即可。

两种方法各有优缺点,针对不同的问题可以根据实际情况选择适合的方法。