Leetcode 2569. 更新数组后处理求和查询
1.题目基本信息
1.1.题目描述
给你两个下标从 0 开始的数组 nums1 和 nums2 ,和一个二维数组 queries 表示一些操作。总共有 3 种类型的操作:
-
操作类型 1 为 queries[i] = [1, l, r] 。你需要将 nums1 从下标 l 到下标 r 的所有 0 反转成 1 并且所有 1 反转成 0 。l 和 r 下标都从 0 开始。
-
操作类型 2 为 queries[i] = [2, p, 0] 。对于 0 <= i < n 中的所有下标,令 nums2[i] = nums2[i] + nums1[i] * p 。
-
操作类型 3 为 queries[i] = [3, 0, 0] 。求 nums2 中所有元素的和。
请你返回一个 数组,包含 所有第三种操作类型 的答案。
1.2.题目地址
https://leetcode.cn/problems/handling-sum-queries-after-update/description/
2.解题方法
2.1.解题思路
带懒标记的线段树
2.2.解题步骤
第一步,基于nums1构建线段树(线段树的实现请看代码及注释)
第二步,计算sums2的和total;遍历queries,在线段树上执行相关操作,并不断更新total
第三步,更新后的total即为题解,返回即可
3.解题代码
python代码
class SegNode():
def __init__(self, id:int):
self.id = id
self.start = 0
self.end = 0
self.sum = 0
self.lazy = 0
def __str__(self):
return f"id = {self.id}, start = {self.start}, end = {self.end}, sum = {self.sum}, lazy = {self.lazy}"
# ==> 带懒标记 求和(变体) 的线段树(节点类实现)
class SegTree:
def __init__(self, nums:list[int]):
# 初始化线段树的存储数组并进行构建二叉平衡线段树(这里采用平衡二叉树,也可以用最大堆进行构建)
self.n = len(nums)
self.nums = nums # 维护原数组的值
self.tree = [SegNode(i) for i in range(self.n * 4)] # 二叉平衡树的范围为4*n,如果使用最大堆的自底向上,则范围2*n即可
self.build(nums, 0, 0, self.n - 1)
# 基础方法:构建树,在node树中,将nums[start:end+1]中的区间元素进行插入(nodeId、start、end确定一个线段树结点)
def build(self, nums:list[int], nodeId:int, start:int, end:int) -> None:
node = self.tree[nodeId]
if start == end:
node.sum = nums[start]
node.start = start
node.end = end
return
mid = (end - start) // 2 + start
# 构建左子树
self.build(nums, nodeId * 2 + 1, start, mid)
# 构建右子树
self.build(nums, nodeId * 2 + 2, mid + 1, end)
# 和形式的线段树;tree[nodeId].sum记录nums[start:end+1]之间元素的和
node.sum = self.tree[nodeId * 2 + 1].sum + self.tree[nodeId * 2 + 2].sum
node.start = start
node.end = end
# 结点懒标记向下推送(基础函数):将node结点的懒标记推送到左右子结点中,并将自身的懒标记清空
def pushDown(self, node:SegNode) -> None:
# 第一步,特殊判断。node结点的懒标记值为0,无需向下推送,直接退出
if node.lazy == 0:
return
# 第二步,获取左右结点的结点编号和范围,更新左右结点的sum和lazy属性
start, end = node.start, node.end
mid = (end - start) // 2 + start
leftChild = self.tree[node.id * 2 + 1]
rightChild = self.tree[node.id * 2 + 2]
if node.lazy % 2 == 1:
leftChild.sum = mid - start + 1 - leftChild.sum
leftChild.lazy += node.lazy
rightChild.sum = end - mid - rightChild.sum
rightChild.lazy += node.lazy
# 第三步,清空node对应的lazy值
node.lazy = 0
def rangeReverse(self, left:int, right:int, nodeId:int) -> None:
node = self.tree[nodeId]
# 第一步,递归退出条件
# 1.1.node结点区间[start,end]和目标区间[left,right]不存在交集时,直接退出
if left > node.end or right < node.start:
return
# 1.2.node结点区间[start,end]被目标区间[left,right]包含,直接更新node的lazy和sum数组。tree中node.sum结点对应值自增;在lazy数组中更新node结点的懒标记,node.lazy自增value
if left <= node.start and right >= node.end:
node.sum = node.end - node.start + 1 - node.sum
node.lazy += 1
return
# 第二步,node区间和目标区间存在重叠的情况下,递归处理
# 2.1.由于需要分到两个子区间中进行递归操作,所以node对应的lazy值需要向下推送到子结点中;本质就是将node结点的lazy值分配到左右结点中,更新node的lazy和sum属性
self.pushDown(node)
# 2.2.递归范围更新两个子树
self.rangeReverse(left, right, nodeId * 2 + 1)
self.rangeReverse(left, right, nodeId * 2 + 2)
# 第三步,更新当前结点的sum值(node中增加value的范围不确定,所以通过子结点来更新)
node.sum = self.tree[nodeId * 2 + 1].sum + self.tree[nodeId * 2 + 2].sum
# 区间查询(基础方法):在结点node对应的[start,end]区间中,求[left,right]区间部分的原数组值的和
def rangeSum(self, left:int, right:int, nodeId:int) -> int:
node = self.tree[nodeId]
# 第一步,递归退出条件
# 1.1.node结点区间和目标区间[left,right]不存在交集时,直接退出
if left > node.end or right < node.start:
return 0
# 1.2.node结点区间被目标区间[left,right]包含,直接返回tree数组中node结点的sum属性
if left <= node.start and right >= node.end:
return node.sum
# 第二步,node区间和目标区间存在重叠的情况下,递归处理
# 2.1.由于需要分到两个子区间中进行递归操作,所以node对应的lazy值需要向下推送到子结点中;本质就是将node结点的lazy值分配到左右结点中,更新node的lazy和sum属性
self.pushDown(node)
# 2.2.递归获取两个子树的范围和,相加进行返回
mid = (node.end - node.start) // 2 + node.start
return self.rangeSum(left, right, nodeId * 2 + 1) + self.rangeSum(left, right, nodeId * 2 + 2)
def __str__(self):
return f"{[t.sum for t in self.tree]}"
class Solution:
def handleQuery(self, nums1: List[int], nums2: List[int], queries: List[List[int]]) -> List[int]:
# 思路:带懒标记的线段树
n = len(nums1)
# 第一步,基于nums1构建线段树
segTree = SegTree(nums1)
# 第二步,计算sums2的和total;遍历queries,在线段树上执行相关操作,并不断更新total
total = sum(nums2)
result = []
for a, b, c in queries:
if a == 1:
segTree.rangeReverse(b, c, 0)
elif a == 2:
total += b * segTree.rangeSum(0, n - 1, 0)
else:
result.append(total)
# 第三步,更新后的total即为题解,返回即可
return result
4.执行结果


浙公网安备 33010602011771号