← 区间查询 · 在数组上反复「问一段、改一点」 / 区间合并:节点存什么,由你定——最大子段和 待审核 5 / 6
advanced · 区间合并

区间合并:节点存什么,由你定——最大子段和

线段树lazy propagation 两页中,节点只缓存一个数(和 / 最小 / 最大)。但节点其实能缓存一组互相关联的量, 只要你能定义「左孩子的信息 + 右孩子的信息 → 父节点的信息」这条合并规则。 经典例子是最大子段和 (maximum subarray sum):数组里有正有负,问某段 [l, r]连续一截的和最大能到多少。它没法只靠一个数往上合—— 跨越中点的那截会被切成两半,单看一侧无法得知另一侧的信息。

关键在于每个节点存四个量,让跨中点的情况也能拼回来:
sum = 整段总和 · pre = 从左端起的最大前缀和 · suf = 到右端止的最大后缀和 · best = 段内任意位置的最大子段和。
合并左右孩子 L、R 时,best 有三个候选:只在左 (L.best)、 只在右 (R.best)、或跨越中点L.suf + R.pre——左的最大后缀接右的最大前缀)。 取最大即可。这第三项正是「区间合并」存在的理由。

1 · 为什么合并顺序不能乱

combine 不满足交换律:L.suf + R.pre 假定 L 在 R 的左边、且两截挨着。 查询 [l, r] 时,被完整盖住的若干极大节点本就从左到右首尾相接,所以严格按这个次序 combineacc,跨节点边界的子段才接得上。换言之:建树时合并的是兄弟, 查询时合并的是命中的连续段,用的是同一个 combine

2 · 实际应用

这类「节点存复合信息 + 自定义合并」的线段树,是竞赛区间题(SPOJ GSS 系列、最大子段和带单点修改)的标配。 工程里同源的思路:区间统计聚合(一段时间窗里的最大连续增长 / 最长连续可用资源)、 磁盘 / 内存的最大连续空闲块查找(合并相邻空闲区间维护「最长连续 0」)、 文本编辑器里区间属性的快速汇总。凡是「答案可能横跨子区间边界、需要边界信息才能拼」的场景,都落在这套框架里。