segment tree beats
segment tree beats
通俗来说一般把这一类问题成为 segment tree beats,可以简称为 beats。
区间最值操作
例题零
- 维护一个序列,支持区间加,区间对一个数 \(v\) 取 \(\min\),单点求值。
直接在线段树维护标记即可,需要注意一下加法操作和取 \(\min\) 操作的顺序。
例题一
- 维护一个序列,支持区间对一个数 \(v\) 取 \(\min\),区间求和。
似乎不太能在线段树上直接维护标记,考虑直接把递归到的区间分成三类:
- 区间最大值 \(mx\leq v\),直接返回即可。
- 区间严格次大值 \(smx<v\leq mx\),此时如果记区间内的最大值个数为 \(cmx\),所有数的和为 \(sum\),那么影响就是 \(sum\leftarrow sum-cmx(mx-v),mx=v\),我们可以直接在线段树上维护标记,含义是把区间内的最大值变成了什么,这个显然可以下传。
- 否则就继续递归。
看起来非常暴力,分析一下复杂度,每次修改一个节点一定会让他的最大值和次大值合并,因此复杂度不会超过所有结点的区间长度和,也就是 \(\Theta(n\log n)\)。
例题二
- 维护一个序列,支持区间加,对一个数 \(v\) 取 \(\min\),区间求和。
在上一题的基础上只需要记录区间内的加法标记即可,论文中证明了这样子的复杂度是 \(\Theta(n\log^2 n)\)。
例题三 BZOJ4695 最假女选手
大致思路差不多,只是麻烦了亿点点,需要同时维护最大值,最小值,严格次大值,严格次小值,以及各种标记,复杂度同上。
例题四 CTSN loves segment tree
大致思路差不多,只是麻烦了亿点点,需要同时维护 \(i\) 是(不是)\(A_i\) 里最大值,\(j\) 是(不是) \(B_j\) 里最大值的 \(A_i+B_j\) 的最大值,复杂度同上。
例题五 【UR #19】前进四
例题六 CF1290E Cartesian Tree
历史最值问题
历史最值问题一般分成三类,历史最大值,历史最小值,历史版本和,以历史版本和为例,其描述为:维护序列 \(A,B\),并在每次操作过后,令 \(B_i=B_i+A_i\),然后查询 \(B_i\) 的区间和。
\(B\) 就是 \(A\) 序列的历史版本和。
例题一
- 维护序列 \(A,B\),对 \(A\) 做区间加,并在每次操作过后,令 \(B_i=B_i+A_i\),然后查询 \(B_i\) 的区间和。
我们考虑在每个线段树节点都用一个队列维护所有标记(区间加标记,以下记为 add 标记;记录历史版本和标记,以下记为 his 标记),然后下传的时候就合并队列,这样当然没问题,不过复杂度爆炸,我们考虑简化一下这个标记队列,找出真正关心的量。
我们维护每个节点的 \(A\) 的和 \(sumA\) 以及 \(B\) 的和 \(sumB\),当从上面传下来一个新的标记序列 \(S\) 时,\(sumA\) 的变化显然是加上 \((\) \(S\) 中的 add 标记的和 \()\times(\)区间长度 \(len)\)。
而 \(B\) 的变化应该是:加上 $sumA\times $$(S$ 中 his 标记的数量),加上( \(S\) 中每次 his 操作前的 add 操作的和)\(\times len\)。
因此我们只需要维护标记序列中 add 操作的和,his 标记的数量,每次 his 操作前的 add 操作的和这三个量即可,复杂度 \(\Theta(n\log n)\)。
对于历史最大值/最小值操作,是类似的,可以自己推一下需要维护什么量。
例题二 【模板】线段树 3(区间最值操作、区间历史最值)
此题还有对 \(A\) 序列的取 \(\min\) 操作,这一部分可以用一开始的做法解决,但是恶心的地方在于这样子需要对于最大值以及非最大值的位置维护两类标记,实现起来更为麻烦。
例题三 P4314 CPU 监控
和上一题没有什么太大区别。
历史最值问题的常见应用
给出序列 \(A\) 以及某种关于区间 \([l,r]\) 的函数值 \(f(l,r)\),\(m\) 次询问,每次给出 \(L,R\),求出 \(\sum\limits_{L\leq l\leq r\leq R} f(l,r)\)。
例如下面的题:
例题四 [NOIP2022] 比赛
本题中 \(f(l,r)=(\max\limits_{i=l}^{i=r}A_i)(\min\limits_{i=l}^rB_i)\)。
这一类问题的通用做法是这样的:
- 对序列扫描线,扫到 \(i\) 时线段树上 \(j\) 位置维护 \(f(j,i)\),那么 \(\sum\limits_{L\leq l\leq r\leq R} f(l,r)\) 就是当扫到 \(i\) 时区间 \([l,r]\) 内所有位置的历史和。
对于本题,我们需要对于所有左端点 \(j\) 维护 \(f(j,i)\),考虑维护 \(A,B\) 的单调栈,这样每次加入 \(i+1\) 时就是弹出若干栈顶元素。
考虑对于每个 \(j\) 维护 \(p_j,q_j\) 表示 \(A\) 序列的后缀 \(\max\) 以及 \(B\) 序列的后缀 \(\min\),那么操作就是对 \(p,q\) 做区间赋值,维护 \(p_i\times q_i\) 的历史和 \(s_i\)。
处理一下就能维护出 \(f(l,r)\) 的和以及历史和了。
- 一种更加好写的写法(但是常数更大)
以例题四为例,我们维护向量 \([1,p_i,q_i,p_iq_i,s_i]\),那么可以发现赋值操作可以写成矩阵乘法的形式,这样子可以减少大量的细节处理,当然代价是常数更大。
例题五:CF1824D LuoTianyi and the Function
较为板子。
例题六 P9990 [Ynoi Easy Round 2023] TEST_90
较为板子。
例题七 [Ynoi2003] 铃原露露
板子的地方很板子。
例题八 [Ynoi2009] rprmq1
太牛的题。

浙公网安备 33010602011771号