如何正确使用 RMQ

本文是笔者上语文课的时候想出来的。后来知道实际上这个东西就是 Four-Rasian。所以仅供参考吧。

序列分块。设块长为 B。每块预处理出最大值。对于询问 [l,r],答案就是整块最大值和散块最大值拼起来。答案显然是 O(n)O(nB+B)。这是普通分块。

我们预处理出每个散块的前缀最大值和后缀最大值。预处理线性。对于跨越两个块的询问就是 O(nB)。但是缺点是对于左右端点在一个块内的询问不好处理,复杂度为 O(B)。根号平衡后还是 O(n)O(n)

我们开一个数组 ml,r,表示第 l 个块到第 r 个块中最大值的最大值。这个数组显然可以很容易的 O((nB)2) 求出。接下来我们预处理所有长度为 O(B) 的段的最大值。用单调队列也很容易做到 O(nB)。这样对于左右端点在同一个块内的询问,其长度一定小于 B。我们可以直接查表。对于跨越多个块的情况,可以查一下 m 数组。这样复杂度是 O((nB)2+nB+n)O(1) 的。根号平衡一下发现当 B=n1/3 的时候有最小值 O(n4/3)O(1)

这似乎是根号算法的极限?

我们考虑 log 算法。首先是众所周知的 ST 表。复杂度 O(nlogn)O(1) ,全方位吊打分块TNT。

我们考虑优化这个算法。考虑分块。不妨还设块长为 B。散块还是求出前后缀的 max,整块之间做一下 ST 表。跨越多块的做法可以做到 O(nBlognB)O(1)。对于单块之间的询问我们沿袭上面分块的思路,直接预处理所有长度为 B 的区间的 max,这样就可以直接查表。所以复杂度就是 O(nBlognB+nB)O(1)。根号平衡一下发现当 B=logn 的时候就可以达到 O(nlogn)O(1)。这比传统意义上的 ST 表要快了。(1)

考虑继续优化这个算法。我们发现瓶颈在处理左右端点在同一块内的答案。在每块内再做一遍 ST 表。这样就需要 O(nB×BlogB)=O(nlogB) 的时间。剩下的算法和原来一样。预处理就变成了 O(nBlognB+nlogB) 了。我们让 B=logn 的时候就已经做到了 O(nloglogn)O(1) 了。当然块长显然可以比这个优秀,但是我不会求了。(2)

这个做法不是很好。我认为做法 (1) 虽然渐进复杂度更劣但是完全有实力吊打做法 (2)

posted @   Link-Cut-Y  阅读(32)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示