RMQ 合集
upd 2021/9/20: 更新。
暴力想必算了。
倍增
或 Sparse Table。
考虑
但是因为 RMQ 问题满足可重复贡献(即
1 |
|
线段树等数据结构
代码想必算了。
猫树
线段树的变种。
对每个树上结点维护前后缀,用 zkw 的方式补全线段树,然后快速算 LCA 什么的。
代码会了但是没必要放这里。
Four Russians
首先把整个序列分成
这样可以把询问分成中间一堆整块,这个可以
对于散块怎么办呢?
再跑一个 ST 表。
没写过。
约束 RMQ
敲黑板:这个是
首先要跑这个东西需要满足一个条件:相邻两数差的绝对值必须为 1(我们一会会去掉这个条件)。
首先考虑 Four Russians 算法,我们发现如果询问有两个散块的话,再对散块使用 ST 表就很蠢了。
我们直接处理一个前缀和后缀就可以加速到
然后考虑两端点在同一块里面的情况。
你思考因为相邻两数差的绝对值为 1,所以差分之后就变成一堆 1 与 -1 。这些形成的序列形成的不同的序列显然只有
似乎没什么用,但我们可以把块弄的更小些:
暴力预处理所以本质不同的块,得到每个区间询问的答案,可以做到
实际上可以进一步调整块长来均摊(当然你要是闲得慌也可以写 ST 处理),不过没什么用。
然后我们思考怎么把一般 RMQ 转化为约束 RMQ。
首先,我们把序列变成一颗笛卡尔树,这样 RMQ 就变成了 LCA,然后对这颗树跑一个欧拉序,那么显然就有相邻两个数差的绝对值为 1。
代码没有因为不实用。
2021/9/20 更新: emm,我星期三学完的约束 RMQ 星期日就直接出现在了初赛考题里。狂暴押题组长
基于状态压缩的伪线性 RMQ
我们发现 Four Russians 的瓶颈在于对块内求 RMQ。
我们考虑单调栈。
啊单调栈有什么性质呢?
越靠前的越大,而且单调栈中的顺序肯定是原先的顺序。
那么如果我们要在单调栈上维护一个后缀,就直接找到在单调栈中第一个在位置上超过某个数的就行。
例如 3 6 2 5 4 1
的单调栈为 6 5 4 1
然后我们要找到 3
的后缀最大值就是 6
,2
的后缀最大值就是 5
。
意会意会真的简单
但是这样只维护了一个后缀,那么右端点的问题就……直接对每个后缀维护一个单调栈。
然后你成功的得到了一个
不过,你发现如果我们把这个东西套到 Four Russians 里面还是可以搞出一个
但是还是非常非常费拉
然后我们注意到
然后我们祭出一个在今年终于可以使用的东西:builtin
。
我们主要使用 __builtin_ctz
(二进制后缀 0 的个数)与 __builtin_clz
(二进制前导 0 的个数)(只用一个也行)。
显然
代码(根据 OI-Wiki 改的,没什么区别):
1 |
|
二次分块实现方式
自己随意口胡的。
这个二次分块实现主要是查询的时候常数更小,大约 1000000
的
没什么好说的,把 ST 表换成根号分块套根号分块,然后对每一层分块暴力求块间答案。
时间复杂度 long long
了,损失的性能基本可以忽略不计,然后可以支持
然后就是 __builtin_
函数的 long long
版本就直接在后面加 ll
就行,例如 __builtin_ctzll
。
代码:
1 |
|