RMQ/稀疏表加速静态区间查询
📅 2026/7/9 1:14:24
👁️ 阅读次数
📝 编程学习
引言
- 静态区间查询问题的定义与应用场景(如数组区间最小值、最大值等)。
- 传统暴力查询的局限性(时间复杂度高)。
- 引入稀疏表(Sparse Table)作为高效静态RMQ的解决方案。
稀疏表的基本原理
- 稀疏表的核心思想:预处理与倍增思想。
- 动态规划预处理数组:定义
st[i][j]表示从索引i开始、长度为2^j的区间极值。 - 状态转移方程:
[ st[i][j] = \min(st[i][j-1], st[i + 2^{j-1}][j-1]) ] - 查询时通过二进制拆分覆盖区间,实现 (O(1)) 查询。
稀疏表的实现步骤
- 预处理阶段
- 初始化
st[i][0]为原数组值。 - 按长度从小到大递推计算
st[i][j]。
- 初始化
- 查询阶段
- 计算区间长度对应的最大幂次
k(满足 (2^k \leq \text{区间长度}))。 - 通过比较两个重叠区间的最小值得到结果:
[ \min(st[l][k], st[r - 2^k + 1][k]) ]
- 计算区间长度对应的最大幂次
代码实现(以C++为例)
int st[MAXN][LOG_MAXN]; // 稀疏表数组 int log2[MAXN]; // 预计算对数表 void preprocess(int n, int arr[]) { for (int i = 0; i < n; i++) st[i][0] = arr[i]; for (int j = 1; (1 << j) <= n; j++) { for (int i = 0; i + (1 << j) <= n; i++) { st[i][j] = min(st[i][j-1], st[i + (1 << (j-1))][j-1]); } } // 预计算log2表(可选优化) log2[1] = 0; for (int i = 2; i <= n; i++) log2[i] = log2[i/2] + 1; } int query(int l, int r) { int k = log2[r - l + 1]; return min(st[l][k], st[r - (1 << k) + 1][k]); }性能分析与实测对比
- 时间复杂度:预处理 (O(n \log n)),查询 (O(1))。
- 空间复杂度:(O(n \log n))。
- 对比其他数据结构:
- 与线段树对比:稀疏表查询更快但不支持动态更新。
- 与树状数组对比:稀疏表更适合纯静态场景。
- 实测数据:展示不同规模数据下稀疏表与暴力查询、线段树的性能差异(如1e6次查询耗时)。
优化与扩展
- 对数表的预计算优化查询常数。
- 扩展到多维稀疏表或支持其他可重复贡献操作(如GCD、按位与等)。
- 结合分块或ST表解决动态RMQ问题。
总结
- 稀疏表的适用场景与局限性。
- 强调其在算法竞赛或高并发静态查询中的优势。
附录
- 相关题目链接(如LeetCode、Codeforces例题)。
- 完整代码与测试数据仓库地址(可选)。
编程学习
技术分享
实战经验