RMQ

RMQ

解释:

RMQ 问题是求给定区间中的最值问题,如下图所示:
RMQ 问题(图中记录的是最小值的位置)
当然,最简单的算法是 O(n)的,但是对于查询次数很多 m(假设有 100 万次),则这个算法的时
间复杂度为 O(mn),显然时间效率太低。可以用线段树将查询算法优化到 O(logn)(在线段树中保
存线段的最值) ,而线段树的预处理时间复杂度为 O(n),线段树整体复杂度为

ST表:

解释:

ST 算法,即 Sparse Table 算法。下面把 ST 算法分成预处理和查询两部分来说明(以求最小值
为例),它的时间复杂度为

1.1.1  预处理:lll
预处理使用 DP 的思想,f(i, j)表示[i, i+2^j ­ 1]区间中的最小值,即 f[i,j]表示从第 i 个数起连
RMQ 和 LCA 
­ 2 ­ 
续 2^j 个数中的最小值。我们可以开辟一个数组专门来保存 f(i, j)的值。
例如,f(1, 0)表示[1,1]之间的最小值,就是 num[1];f(1, 2)表示[1, 4]之间的最小值, f(2, 4) 
表示[2, 17]之间的最小值。
注意, 因为 f(i, j)可以由 f(i, j  ­  1)和 f(i+2^(j­1), j­1)导出, 而递推的初值(所有的 f(i, 0) 
=num[i])都是已知的。所以我们可以采用自底向上的算法递推地给出所有符合条件的 f(i, j)的值。
ST 算法(图中记录的是最小值的位置) 
ST 算法的状态转移方程:
1 
[ ] , 0 
( , )
min ( ( , 1), ( 2 , 1), 0
j 
a i j  f i j  f i j f i j j -
Ï =
= Ì
Ó - + - >
例 如 : f(2,3) 保 存 的 是 a[2],a[3],a[4],……,a[9] 中 的 最 小 值 , 而
f(2,3)=min(f(2,2),f(6,2))=min((a[2],a[3],a[4],a[5]),(a[6],a[7],a[8],a[9]))
1.1.2  查询:
假设要查询从 m  到 n  这一段的最小值,  那么我们先求出一个最大的 k,  使得 k  满足
2 ( 1)
k £ n - m + ,于是我们就可以把[m,  n]分成两个(部分重叠的)长度为 2
k
的区间:
[ , 2 1]
k
m m + - , [ 2 1, ]
k
n - + n ; 
而 我 们 之 前 已 经 求 出 了 f (m, k ) 为 [ , 2 1]
k  m m + - 的 最 小 值 , ( 2 1, )
k f n - + k 为
[ 2 1, ]
k
n - + n 的最小值。
我们只要返回其中更小的那个, 就是我们想要的答案, 这个算法的时间复杂度是 O(1)的。
RMQ 和 LCA 
­ 3 ­ 
k= trunc(ln(r­l+1)/ln(2)); // 求[l,r]之间的最小值
ans:=max(F[l,k],F[r­2^k+1,k]);
例如, rmq(1,12) = min(f(1,3), f(5,3)) ( 2 k = log (12 -1+1) = 3 ) 
ST 算法的 O(1)查询(有部分重叠)
function max(x,y: longint): longint;
begin
max:=x;
if y>x then max:=y;
end;
function query(s,t: longint): longint;  // 查询[s,t]间的最大值
var
k: longint;
begin
k:=trunc(ln(t­s+1)/ln(2)); 
query:=max(a[s,k],a[t­(1<<k)+1,t]);  // 即max(a[s,k],a[t­2^k+1,t])
end;
procedure init;
var
i,j,p: longint;
begin
assign(input,'rmq­st.in');
reset(input);
readln(n);
for i:=1 to n do read(a[i,0]); 
p:= trunc(ln(n)/ln(2));
for j:=1 to p do // a[i,j]表示从i开始,2^j个元素的最大值
for i:=1 to (n­(1<<j)+1) do // n­(1<<j)+1 即 n­2^j+1 
a[i,j]:=max(a[i,j­1],a[i+1<<(j­1),j­1]);
close(input);
end;

1.2 巧妙易实现的分块 ­­ sqrt(n)算法: (★★★)

把数组分割成 sqrt(n)大小的段。用一个数组 M[1..sqrt(n)]为每一段保存最小值(或位置)。
M 可以很容易在 O(n)时间内完成预处理。
如在上例中,计算 RMQ(3,8)的值,我们应该比较 A[3]、M[2]、A[7]、A[8]值即可。可以很容
易看出这个算法每一次查询不会超过 3*sqrt(n)次操作。
这个方法非常容易实现,并且还可以将它改成问题的动态版本 .... (边查询、边改元素)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值