比较纯粹的分块线段树等 DS 趣题
要你求一个区间的最大子段和。
那么,显然地,我们可以维护区间最大前缀和和后缀和。
即根据左区间后缀和加上右区间前缀和可以等于最大子段和这个性质。
那么如何维护最大前缀和和最大后缀和呢?
显然一段区间分成两块,最大前缀和有可能是左区间的最大前缀和,也有可能是左区间的 Sum 加上右区间的最大前缀和,那么这样想,右区间也就没有疑问了。
然后正常操作即可。
1 |
|
带修区间最大子段和。
。没什么好说的了。
1 |
|
Update 区间开方,Query 区间和。
那么根据某上帝造题的套路,因为 $\sqrt{1}=1$,所以可以维护一个区间 Max。
如果当前区间 Max = 1,那么直接退出循环,停止修改。
然后 pushdown 的时候 lazytag 下传一下。
没别的了。
1 |
|
区修单查。
直接维护一个块内加法的 tag 和零散块的 tag 即可。
零散块为了方便可以直接加在原数组里面。
1 |
|
区间修改,区间查询 $<k$ 的数的个数。
不难想到直接块内排个序就没了。
这个时候就要考虑零散块了。
因为排了序,所以原来的下标都换了位置。
那么我们可以暴力一点,直接在输入的数组里面进行修改,在这之后把零散块所在的区间全部重新赋值一遍,然后再块内排个序即可。可以保证这个是正确的,因为区间 tag 是区间统一加上,所以原来的相对关系都没有变,所以是对的!
那么要注意的是,query 的时候查询零散块要查询输入数组而非块内已排序的数组。
为什么?还是那个 id 变化的问题,下标不一样嘛。
我才不会告诉你就是这个问题卡了我好久
1 |
|
区间加法,区间前驱。
简单题。每一次区间加法直接加到 tag 里面去。
然后区间前驱对于每一个块都扫一遍 lower_bound
。
接着零散块暴力扫。取一个 Max 即可。
注意零散块扫的是原来的数组,update 完之后要重新更新左右两个块。
以及不要忘记在求前驱的时候加上 tag
。
1 |
|
区间加法,区间求和。
直接记录一下块内的和 Sum 即可。
然后维护一个 tag,和原数组 a,查询暴力查询即可。
1 |
|
区间开方,区间求和。
因为一个数最多被开方多少多少次(懒得算),所以直接类比线段树做法。
对于每一个块如果 Max $\le 1$ 了直接跳过,根本不需要开方。
否则直接暴力修改整个块,更新 Sum 数组即可。
1 |
|
单点插入,单点查询。
对于每一个块维护一个 vector 和 siz。
然后对于每一个插入操作,直接插入 vector 即可,siz 更新。
单点查询只要将查询的 id 遍历一遍减掉 siz 看什么时候满足当前 siz 即可。
插入操作也是一样。
1 |
|
区间加,区间乘,单点查询。
直接参考线段树加法乘法操作即可。
首先优先级肯定乘法大于加法,所以考虑维护两个 tag。
即 addtag 和 multag。
然后区间加和区间乘最重要的就是类似于 pushdown 之类的东西。
就是根据优先级直接将当前区间标记下放乱搞即可。
1 |
|
比较纯粹的分块线段树等 DS 趣题