RMQ

1、概述

RMQ(Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。其实我们也可以使用线段树的方法,对于需要修改元素的区间查找,线段树较优,但是他代码长,细节多,所以有必要学习一门容易的算法。

2、什么是RMQ?能吃吗?怎么用?

对于如上的问题,我们可以根据给出的[Li,Ri],每次进行O(n)的枚举查找。但是如果查找的次数非常多,且N的范围很大,显然是会超过时间复杂度的。下面介绍一种比较容易的ST算法(Sparse Table),这是一个非常有名的在线实现RMQ问题的算法。它可以在O(nlogn)的时间内进行预处理,然后在O(logn)的时间里查询(可能不需要这么多)。

RMQ算法具体实现

(一)首先必须是预处理,在此使用动态规划实现

我们设A[i]表示我们需要查询的区间。F[i,j]表示从第i个位置开始,往后连续2^j个数中的最大值

例如:

a={3,2,4,5,6,8,1,2}

可以看出,刚开始f[i,0]是等于a[i]的(从第i个位置开始的1个数字,即本身)

这样,DP的状态和初始值都已经想出来了,如何转移?

我们可以把f[i,j]分成两份(因为2^j次方个数一定是偶数),如下图:


平均分后每一段都有2^(j-1)个,分别是 i~i+2^(j-1)-1 和 i+2^(j-1)~i+2^j-1 再根据状态得知,第一段即是f[i,j-1],第二段就是f[i+2^(j-1),j-1],我们当前求最大值,就是从f[i,j-1]以及f[i+2^(j-1),j-1]中选取一个较大值赋值给f[i,j]。

于是我们就得到了状态转移方程f[i,j]:=max(f[i,j-1,f[i+2^(j-1),j-1]);

举个栗子: 

F[1,1] = max(3,2) = 3, F[1,2]=max(3,2,4,5) = 5,F[1,3] = max(3,2,4,5,6,8,1,2) = 8。

代码如下:

for j:=1 to 17 do//log(n),代码中n为100000,power[j]即2^j
        for i:=1 to n do
                if power[j-1]+i<=n then//在符合条件内
                        f[i,j]:=max(f[i,j-1],f[power[j-1]+i,j-1]);
聪明的你会发现,这里的J是在外循环的,为啥子呢?我们通过两个方面去思考。

1、赋值

我们每次需要f[i,j-1],f[2^(j-1)+i,j-1],如果我们i在外循环,那么f[2^(j-1)+i,?]是没有值的,因为i是根本没有到达那个位置,所以是不可行的。

2、转移的含义

状态转移方程的含义是:先更新所有长度为F[i,0]即1个元素,然后通过2个1个元素的最值,获得所有长度为F[i,1]即2个元素的最值,然后再通过2个2个元素的最值,获得所有长度为F[i,2]即4个元素的最值,以此类推更新所有长度的最值。而如果是i在外,j在内的话,我们更新的顺序就是F[1,0],F[1,1],F[1,2],F[1,3],表示更新从1开始1个元素,2个元素,4个元素,8个元素(A[0],A[1],....A[7])的最值,这里F[1,3] = max(max(A[0],A[1],A[2],A[3]),max(A[4],A[5],A[6],A[7]))的值,但是我们根本没有计算max(A[0],A[1],A[2],A[3])和max(A[4],A[5],A[6],A[7]),所以这样的方法肯定是错误的。

为了避免这样的错误,一定要好好理解这个状态转移方程所代表的含义。

(二)如何查找,给定[Li,Ri]不会查找,有什么用?

我们查找[Li,Ri],我们首先要找出这个区间数的最大的二的幂,即log

如你要找第5,6,7,8,9个数之中的最大值,有5个数,最大幂是2^2,你就得取两组长度为4的值,一个是从Li起连续的4个数最大值(5,6,7,8),以及Ri起向前的4个数的最大值(6,7,8,9),求他们的最大值之即可。

因为这里已经覆盖了需要找的Li,Ri区间的所有值
代码如下:

readln(l,r);
for j:=1 to 17 do
        if power[j]>r-l+1 then
        begin
                maxn:=j-1;
                break;
        end;//寻找最大幂

writeln(max(f[l,maxn],f[r-power[maxn]+1,maxn]));//输出结果
RMQ到此为止,大家不懂可以在评论提问,亦可以指出我的问题所在,谢谢。

猜你喜欢

转载自blog.csdn.net/fengyingjie2/article/details/54347663
RMQ