Skip to content

算法Algorithm

线性预处理常数时间 RMQ

施工中 · 内容逐步修订

Constant-time RMQ · Farach-Colton–Bender RMQ · 线性 RMQ

将一般静态 RMQ 归约为深度差为正负一的数组,再用微块类型查表与宏块稀疏表实现线性预处理、常数查询。

形式陈述 ​

接口与归约后的规模 ​

给定长度 n≥1 的静态数组 A,回答RMQ:对 0≤l<r≤n,返回半开区间 [l,r) 的最左最小值位置。空数组没有合法的非空查询,可以直接保存空结构。假设键比较为常数时间,机器字能容纳下标,并在Word-RAM上支持常数时间位运算和表寻址。目标是 O(n) 预处理、O(n) 字空间和 O(1) 最坏查询。

先按 (A[i],i) 的字典序建立最小笛卡尔树 C(A)。RMQ–LCA 归约给出

RMQA(l,r)=LCAC(A)(l,r−1).

完整 Euler walk 记录顶点 E[j]、深度 D[j] 和每个顶点首次出现位置。令

m=|D|=2n−1.

相邻两次记录沿一条树边上下移动,所以 D[j+1]−D[j]∈{−1,+1}。两顶点首次位置之间的最小深度记录对应其 LCA。树、walk 和首次位置表均可在线性时间构建;下面所有微块数量都按实际深度数组长度 m 计算。

微块类型与查表 ​

常数小的 m 直接处理。其余情况取

b=max(1,⌊12log2⁡m⌋)

并把 D 分成长度至多 b 的连续块。满块减去首深度后,只由 b−1 个正负一增量决定,因此共有 2b−1=O(m) 种类型。

每种类型的所有相对区间 [p,q) 都有固定的最左最小位置。先还原它的相对深度,再对每个起点逐步延长右端、维护当前最左最小位置,就能在 O(b2) 时间填好该类型的所有答案。全部微表的时间与空间为

O(2bb2)=O(mlog2⁡m)=o(m).

最后一个短块按长度和类型共同编号;把所有较短长度也求和,仍为 O(2bb2)。

类型编码占至多 b−1 bit,实际块还保存首深度和全块最小值位置。类型与两个块内端点可放入常数个机器字,一次局部查询通过表寻址取得相对位置,再加上块起点。扫描时同时为每个位置记录所属块号和块内偏移,查询便不依赖额外的常数时间整数除法。实际块的编码、位置表与最小值扫描总计 O(m) 工作。

宏结构 ​

实际微块数是

N=⌈mb⌉.

宏数组 M[j] 保存第 j 块的最左最小位置,并按 (D[M[j]],M[j]) 比较。对这 N 项建立稀疏表,其预处理和空间为

O(Nlog⁡(N+1))=O(m),

因为 b=Θ(log⁡m),宏数组缩小了一个对数因子。同时为宏区间长度预存下整对数,宏查询只需常数次表访问和比较,返回连续完整块中的最左最小位置。

总成本由一般数组归约 O(n)、实际深度块扫描 O(m)、通用微表 o(m) 和宏表 O(m) 组成。用 m=2n−1 换回原输入规模,得到 O(n) 预处理和空间。

直觉

一般 RMQ 先借 Cartesian tree 与 Euler walk 变成相邻深度只差一的数组,这一步把任意数值大小消去,只留下有限的局部形状。微块用形状编号查表,宏结构只看每块最小值;块长取半个对数,恰好让全部形状表是低阶空间,而缩小后的宏稀疏表仍只有线性规模。

图中直接给定长度256的正负一数组,图内标注 n=256 对应上文的深度数组长度 m,所以块长为4。图示查询 [2,11) 的三个候选位置为3、7、8,最小值在位置7。

例子与边界

查询分成至多三个候选 ​

若 [l,r) 落在同一微块,直接查该类型的局部表。否则令左块编号为 i=⌊l/b⌋、右块编号为 j=⌊(r−1)/b⌋,再把区间分为:

  1. 从 l 到其微块末尾的左残块;
  2. 中间若干完整微块;
  3. 右侧微块开头到 r 的右残块。

左右残块各做一次微表查询,中间部分做一次宏稀疏表查询;比较至多三个候选的 (D[i],i),返回最左者,查询最坏 O(1)。

例如一个查询从第 j 块中部进入、在第 j+3 块中部结束,算法不会逐项扫描四个块:只查第 j 块的后缀、第 j+1 到 j+2 两个整块的宏答案,以及第 j+3 块的前缀。三个答案覆盖查询区间且互不遗漏。

失败边界与近邻方案 ​

类型数 2b−1 依赖相邻深度差恰为 ±1。一般数值块即使减去首值仍可能有巨大类型空间,不能原样查表;一般 RMQ 必须先通过 Cartesian tree 与 Euler tour 获得这条特殊结构。

通用类型表可以按机器规模共享,也可以计入当前实例;即使逐实例构造,它也是 o(n)。若机器字装不下类型编码、表寻址不是常数时间,或表被视为不可用的非一致 advice,模型已经改变,O(1) 查询结论需重新解释。

稀疏表本身预处理简单但占 O(nlog⁡n);本结构用微宏分解把它只放在缩小后的宏数组上。线段树支持更新却只能给对数查询。这里的最优界严格属于静态 RMQ,数组一旦点更新,Cartesian tree、块类型和宏最小值都可能同时失效。

推论与应用

微块层把短块的正负一深度差分编码成有限类型,再用四俄罗斯方法与字级并行为每种类型预计算所有块内查询。宏观层仍需处理块间 RMQ,两层共同达到线性预处理与常数查询。

该结构给静态 RMQ 达到线性预处理、线性空间与常数最坏查询,并经 RMQ–LCA 等价用于最近公共祖先、后缀数组 LCP 查询和简洁树导航。若需要更新,应改用线段树等动态结构;常数查询界依赖的 Word-RAM 与通用微表假设也必须随应用一并声明。

参考资料
  • Michael A. Bender and Martín Farach-Colton, “The LCA Problem Revisited,” LATIN 2000, LNCS 1776, 88–94.
  • Johannes Fischer and Volker Heun, “Theoretical and Practical Improvements on the RMQ-Problem, with Applications to LCA and LCE,” CPM 2006.
  • Dov Harel and Robert E. Tarjan, “Fast Algorithms for Finding Nearest Common Ancestors,” SIAM Journal on Computing 13(2), 1984.
关系图谱10 个相邻概念 · 3 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系