RMQ问题(区间求最值)

一.简介

  RMQ是英文Range Maximun(Minimum) Query 的缩写,顾明思义是询问某个区间内的最大值或最小值。下面讲解RMQ的求解方法-ST算法。

  ST算法通常用在多次询问一些区间的最值的问题中。相比于线段树,它的程序实现更简单,运行速度更快,它可以做到O(nlogn)的预处理,O(1)回答每个询问。

  使用ST算法的条件是没有修改操作,因此它适用于没有修改操作并且询问次数多(10^6级别甚至更大)的情况。

二.ST算法流程

 1.预处理

   ST算法的原理实际上是动态规划,我们用a[1...n]表示一组数。设f[i,j]表示从a[i]到a[i + 2^j - 1]这个范围内的最大值,也就是以a[i]为起点连续2^j个数的最大值。由于元素个数为2^j个,所以从中间平分成两部分,每一部分的元素个数刚好为2^(j-1)个,也就是说,把f[i , j]分为f[i,j - 1]和f[i + 2^(j-1) , j - 1],如图所示

   
 

 整个区间的最大值一定是左右两部分最大值的较大值,满足动态规划的最优化原理分析得到状态转移方程:f[i][j]=max(f[ i ][j - 1],f[ i + 2^(j-1) ][ j - 1 ]),边界条件为f[i][0]=a[i],这样就可以在O(nlogn)的时间复杂度内预处理f数组。

 2.询问

  若我们要询问区间[ l, r] 的最大值,则先求出最大的x满足2^x <=r-l+1,那么区间[ l , r ]=[ l , l + 2^x - 1] U [ r - 2^x + 1 , r]。

两个区间的元素个数都为2^x ,所以[l , r] 的最大值为max(f[l][x],f[r - 2^x + 1][x]) ,可以在O(1)内计算出来。虽然这两个区间有交集,但是对于求区间最值来说没有影响,这就是ST算法只适用于求区间最值的原因。

  求区间[x , y] 最大值,直接给出表达式:

 k=log2(y-x+1); 

ans=max(f[x][k],f[y - 2^k + 1][k])

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define MAX 1000005
#define N 30
int Log[MAX],ans[MAX][N],num[MAX];
int n,que,x,y;
int main()
{
    int i,j,c,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        Log[0]=-1;
        for(i=1;i<=n;i++)
        {
            ans[i][0]=num[i];
            Log[i]=Log[i>>1]+1;
        }
        for(j=1;j<=N;j++)
        {
            for(i=1;i+(1<<j)-1<=n;i++)
            {
                ans[i][j]=max(ans[i][j-1],ans[i+(1<<j-1)][j-1]);
               //若求最小值就是min()
            }
        }
        scanf("%d",&que);
        while(que--)
        {
            scanf("%d%d",&x,&y);
            int temp=Log[y-x+1];
            printf("%d\n",max(ans[x][temp],ans[y-(1<<temp)+1][temp]));
        }
    }
    return 0;
}

                                                                                                                                 摘自《信息学奥赛一本通 提高篇》

猜你喜欢

转载自blog.csdn.net/ZCMU_2024/article/details/81606068