目录
- 修改: 替换区间
的值为t - 查询: 区间最大值
- 查询: 区间和
敏锐的观察到
- 被替换的数字不可能变的更大
- 每次替换,都会使不同的数字的个数变少(或不变)
- 所有的数字都一样时,利用线段树的区间操作性质,操作次数是
- 数字相同个数越多,区间操作次数越少.
严格次最大值se_max,是子树的最大值,若子树的最大值与max相同,则
复杂度计算
证明吉司机线段树(Segment Tree Beats)的复杂度是
这是算法竞赛中一个非常精彩的证明。为了让你直观理解,我们不堆砌复杂的数学符号,而是通过**“颜色段(Tag Class)”**的概念来从本质上进行推导。
1. 核心模型:颜色段(Tag Class)
我们要定义一个势能函数 max_val 等于它父节点的 max_val,我们就把它们染成相同的颜色。
- 同色连通块:最大值相同且相连的一片节点集合。
- 势能
:定义为整棵线段树中同色连通块的数量。
初始状态:最坏情况下,每个节点的最大值都不同,连通块数量最多为
2. 操作对势能的影响
我们要证明:总的时间复杂度
我们回顾三种情况:
情况 A:u.max_val <= t (剪枝)
直接返回。时间
情况 B:u.se_max < t < u.max_val (打标记)
- 操作:我们将当前节点
的 max_val修改为。 - 对势能的影响:
- 节点
原本属于某个“最大值为 ”的连通块。 - 现在
的最大值变成了 。 - 这可能会让
和它的子节点断开(如果子节点最大值没变),也可能让 和父节点断开,或者重新融合。 - 关键点:这种情况只发生在递归的终止节点。根据线段树的性质,一次区间操作最多会有
个这样的终止节点。 - 即使这里增加了新的连通块,数量也是
级别的。
- 节点
情况 C:t <= u.se_max (暴力递归)
这是我们最担心的“复杂度黑洞”。
- 发生条件:当前连通块(最大值为
)必须被“打破”。因为 比次大值还小,说明这个操作不仅仅是修改最大值那么简单,它会深入到连通块的内部。 - 对势能的消耗:
- 当我们被迫从节点
向下递归到 的左右子节点时,意味着 原本所在的这个“同色连通块”在 这里被打断了。 - 或者更准确地说,吉如一(Jiry_2)证明了:每一次发生的额外递归(Case 3),在均摊意义上,都会导致至少一个同色连通块被破坏(势能减 1)。
- 因为递归下去后,子节点的
max_val会被更新为新的值,而这个新值往往会与原子树的结构不同,导致旧的连通结构解体。
- 当我们被迫从节点
3. 势能账单(复杂度计算)
我们可以把复杂度看作是“消费势能”的过程:
-
存款(势能增加):
- 每次区间操作,我们标准的线段树访问(访问区间边界)会经过
个节点。 - 这些访问可能会把原本连在一起的同色块“切开”,导致连通块数量增加。
- 结论:每次操作最多增加
的势能。 次操作,总共增加的势能上限是 。
- 每次区间操作,我们标准的线段树访问(访问区间边界)会经过
-
消费(暴力递归):
- 每一次执行 Case 3 的暴力递归,都需要消耗至少 1 个单位的势能(破坏连通块)。
- 既然总的势能(初始 + 新增)只有
。 - 那么,Case 3 发生的总次数就不可能超过
。
4. 为什么必须是“严格”次大值?
如果不是严格次大值,上面的势能分析就失效了。
- 如果
se_max == max_val,那么t < max_val时可能依然满足t <= se_max,导致 Case 3 频繁触发。 - 但这并没有“破坏”任何连通块结构(因为值是一样的),势能没有减少。
- 势能不减少,递归却在继续,复杂度就会无限膨胀退化成
。 - 严格次大值 保证了:只要我递归了,我就一定确实地缩小了数值的“贫富差距”,确实地破坏了原有的结构。
结论
吉司机线段树(仅含区间最值操作)的时间复杂度由两部分组成:
- 基础开销:标准的线段树操作
。 - 额外递归开销:受限于总势能
。
两者相加,总复杂度依然是
(注:如果题目再变态一点,加上“区间加法”操作,势能函数会变得非常复杂,需要维护历史标记,复杂度会退化到