区间最值操作 & 区间历史最值
本文讲解吉老师在 2016 年国家集训队论文中提到的线段树处理历史区间最值的问题。
区间最值
笼统地说,区间最值操作指,将区间
HDU5306 Gorgeous Sequence
维护一个序列
:
0 l r t
。 1 l r
输出区间中的最大值。 2 l r
输出区间和。多组数据,
。
区间取 min,意味着只对那些大于
- 如果
,显然这个 是没有意义的,直接返回; - 如果
,那么这个 就能更新当前区间中的最大值。于是我们让区间和加上 ,然后更新 为 ,并打一个标记。 - 如果
,那么这时你发现你不知道有多少个数涉及到更新的问题。于是我们的策略就是,暴力递归向下操作。然后上传信息。
这个算法的复杂度如何?使用势能分析法可以得到复杂度是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
|
BZOJ4695 最假女选手
长度为
的序列,支持区间加 /区间对 取 /区间对 取 /求区间和/求区间最大值/求区间最小值。
。
同样的方法,我们维护最大、次大、最大个数、最小、次小、最小个数、区间和。除了这些信息,我们还需要维护区间
- 我们认为区间加的标记是最优先的,其余两种标记地位平等。
- 对一个结点加上一个
标记,除了用 更新卫星信息和当前结点的区间加标记外,我们用这个 v 更新区间 和区间 的标记。 - 对一个结点取
的 (这里忽略暴搜的过程,假定标记满足添加的条件),除了更新卫星信息,我们要与区间 的标记做比较。如果 小于区间 的标记,则所有的数最后都会变成 v,那么把区间 的标记也变成 。否则不管。 - 区间取 v 的
同理。
另外,BZOJ 这道题卡常……多数组线段树的常数比结构体线段树的常数大……在维护信息的时侯,当只有一两个数的时侯可能发生数集重合,比如一个数既是最大值又是次小值。这种要特判。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
|
吉老师证出来这个算法的复杂度是
Mzl loves segment tree
两个序列
,一开始 中的数都是 。维护的操作是:
- 对
做区间取 - 对
做区间取 - 对
做区间加 - 询问
的区间和 每次操作完后,如果
的值发生变化,就给 加 。 。
先考虑最容易的区间加操作。只要
对于区间取最值的操作,你发现你打标记与下传标记是与
CTSN loves segment tree
两个序列
:
- 对
做区间取 - 对
做区间取 - 对
做区间加 - 对
做区间加 询问区间的
的最大值
。
我们把区间中的 位置 分成四类:在
复杂度仍是
小结
在第本章节中我们给出了四道例题,分别讲解了基本区间最值操作的维护、多个标记的优先级处理、数集分类的思想以及多个分类的维护。本质上处理区间最值的基本思想就是数集信息的分类维护与高效合并。在下一章节中,我们将探讨历史区间最值的相关问题。
历史最值问题
历史最值不等于可持久化
注意,本章所讲到的历史最值问题不同于所谓的可持久化数据结构。这类特殊的问题我们将其称为历史最值问题。历史最值的问题可以分为三类。
历史最大值
简单地说,一个位置的历史最大值就是当前位置下曾经出现过的数的最大值。形式化地定义,我们定义一个辅助数组
这时,我们将
历史最小值
定义与历史最大值类似,在
历史版本和
辅助数组
我们称
接下来,我们将历史最值问题分成四类讨论。
可以用标记处理的问题
CPU 监控
序列
一开始相同:
- 对
做区间覆盖 - 对
做区间加 - 询问
的区间 - 询问
的区间 每次操作后,我们都进行一次更新,
。 。
我们先不考虑操作 1。那么只有区间加的操作,我们维护标记
这个定义可能比较模糊。因此我们先解释一下标记的生存周期。一个标记会经历这样的过程:
- 在结点
被建立。 - 在结点
接受若干个新的标记的同时,与新的标记合并(指同类标记) - 结点
的标记下传给 的儿子, 的标记清空
我们认为在这个过程中,从 1 开始到 3 之前,都是结点
为什么要定义生存周期?利用这个概念,我们可以证明:在一个结点标记的生存周期内,其子结点均不会发生任何变化,并保留在这个生存周期之前的状态。道理很简单,因为在这个期间你是没有下传标记的。
于是,你就可以保证,在当前标记生存周期内的历史
那么信息的更新也是类似的,拿对应的标记更新即可。
接下来,我们考虑操作 1。
区间覆盖操作,会把所有的数变成一个数。在这之后,无论是区间加减还是覆盖,整个区间的数仍是同一个(除非你结束当前标记的生存周期,下传标记)。因此我们可以把第一次区间覆盖后的所有标记都看成区间覆盖标记。也就是说一个标记的生存周期被大致分成两个阶段:
- 若干个加减操作标记的合并,没有接收过覆盖标记。
- 覆盖操作的标记,没有所谓的加减标记(加减标记转化为覆盖标记)
于是我们把这个结点的 Pre 标记拆成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
|
本页面最近更新:2023/3/22 15:46:23,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:CCXXXI, countercurrent-time, Enter-tainer, H-J-Granger, hsfzLZH1, ImpleLee, kenlig, NachtgeistW, opsiff, ouuan, sshwy, StudyingFather, SukkaW, Xeonacid
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用