区间内最大连续和查询(基于线段树的分治方法)
字数 1531 2025-10-26 19:15:22
区间内最大连续和查询(基于线段树的分治方法)
题目描述
给定一个整数数组,需要处理两种操作:
- 更新操作:修改数组中某个位置的值。
- 查询操作:查询某个区间内的最大连续子数组和(即该区间内连续元素的和的最大值)。
例如,数组 [1, -3, 2, 4, -1] 中,区间 [0, 4] 的最大连续和为 6(子数组 [2, 4] 的和)。要求设计一个高效算法,支持多次更新和查询操作。
解题过程
步骤1:理解问题难点
直接暴力计算每次查询需要 O(n²) 时间(枚举所有子数组),但若频繁查询和更新,效率极低。目标是将每次查询和更新优化到 O(log n) 时间,需借助线段树(Segment Tree)并维护特殊信息。
步骤2:线段树节点设计
每个节点代表一个区间 [l, r],存储以下四个值:
sum:区间内所有元素的和。maxPrefix:区间内最大前缀和(从l开始的连续子数组和的最大值)。maxSuffix:区间内最大后缀和(以r结尾的连续子数组和的最大值)。maxSum:区间内最大连续子数组和。
例如,区间 [2, 4, -1] 的四个值分别为:
sum = 5maxPrefix = 6(从首元素开始的最大和是2+4=6)maxSuffix = 5(以末元素结束的最大和是4+(-1)+2?错误!正确计算:后缀包括自身,因此从右向左累加,-1+4+2=5)maxSum = 6(子数组[2,4]的和)。
步骤3:合并左右子区间
设左子节点 L 代表 [l, mid],右子节点 R 代表 [mid+1, r],父节点 P 的值计算如下:
P.sum = L.sum + R.sumP.maxPrefix = max(L.maxPrefix, L.sum + R.maxPrefix)
(最大前缀要么在左半部分,要么跨越左右两部分)P.maxSuffix = max(R.maxSuffix, R.sum + L.maxSuffix)
(最大后缀要么在右半部分,要么跨越左右两部分)P.maxSum = max(L.maxSum, R.maxSum, L.maxSuffix + R.maxPrefix)
(最大连续和可能完全在左半、完全在右半,或跨越中间边界)。
步骤4:建树与初始化
- 叶子节点:区间长度为1时,
sum = maxPrefix = maxSuffix = maxSum = 单元素值。 - 递归构建左右子树,然后按步骤3合并。
- 时间复杂度:O(n)。
步骤5:更新操作
- 从叶子节点开始更新值,向上递归更新父节点,每次按步骤3重新计算四个值。
- 时间复杂度:O(log n)。
步骤6:查询操作
- 查询区间可能覆盖多个节点,需递归合并部分区间。
- 若查询区间完全覆盖当前节点,直接返回该节点的四个值。
- 若查询区间部分覆盖左右子树,分别查询左右子树,得到
L和R后,按步骤3合并为一个节点返回。 - 时间复杂度:O(log n)。
步骤7:示例验证
数组 [1, -3, 2, 4, -1] 查询 [0,4]:
- 递归合并所有叶子节点后,根节点的
maxSum=6(对应子数组[2,4])。 - 若更新索引2的值为
3,数组变为[1,-3,3,4,-1],重新计算后[0,4]的maxSum=7(子数组[3,4])。
总结
通过线段树维护每个区间的四个关键值,将动态区间最大连续和问题转化为 O(log n) 的更新和查询,适用于需要频繁操作的场景。