码迷,mamicode.com
首页 > 其他好文 > 详细

RMQ1

时间:2019-02-08 21:59:07      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:++   技术   阅读   nlog   ==   长度   ima   print   最大的   

RMQ这种算法,有好处也有坏处。

好处是代码量比其他算法(线段树,树状数组等)稍短(又是很短),坏处是局限性太大,不如线段树灵活。

它的目的是求区间最值。

我们先看一道简单题。

有一个序列,以及一些操作,每次操作给出一个区间[l,r],求这个区间的最大值。

如果你之前阅读技术图片

 

或其他有关线段树的资料,这题就是小菜一碟。

当我们摆脱线段树,从另一个视角看这题。

我们把它想成一道区间DP,用dp[i][j]表示区间[i,j]的最大值。

显而易见,有dp[i][j]=max(dp[i][j-1],a[i])(时间复杂度O(n^2))

我们采用倍增思想,用dp[i][j]表示以i为起点,长度为2j的区间最大值,求解时分成两个区间[i,i+2j-1-1],[i+2j-1,i+2j+1]

有dp[i][j]=max(dp[i][j-1],dp[i+2j-1][j-1])

由于长度为2j,时间复杂度为O(nlogn)

以上是预处理部分。

实际查询时,我们需要求解一个任意的区间,而上面的预处理只能求出长度为2j的区间最大值。

我们利用一下一个小性质:
技术图片

我们的目标就是要把待查询的区间,转化成两个我们已经求出的区间。

找出最大的2k<=len的k,其中len=r-l+1为区间长度,取区间[l,l+2k-1],[r-2k+1,r]为两个小区间,显然满足且能找到,时间复杂度为O(1)

模板题代码:

#include<bits/stdc++.h>

#define rd(x) x=read()
#define N 100005 

using namespace std;

int n,m;
int a[N][25];

inline int read()
{
    int f=1,x=0;char s=getchar();
    while(s<0||s>9){if(s==-)f=-1;s=getchar();}
    while(s>=0&&s<=9){x=x*10+s-0;s=getchar();}
    return x*f;
}

int query(int l,int r)
{
    int k=log2(r-l+1);
    return max(a[l][k],a[r-(1<<k)+1][k]);
}

int main()
{
    rd(n);
    for(int i=1;i<=n;i++)rd(a[i][0]);
    for(int j=1;j<=21;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            a[i][j]=max(a[i][j-1],a[i+(1<<(j-1))][j-1]);
    rd(m);
    while(m--)
    {
        int l,r;
        rd(l),rd(r);
        printf("%d\n",query(l,r));
    }
    
    return 0;
}

 

是不是感觉RMQ很方便呢,RMQ还有许许多多的拓展,下期再见!

 

RMQ1

标签:++   技术   阅读   nlog   ==   长度   ima   print   最大的   

原文地址:https://www.cnblogs.com/Robin20050901/p/10311438.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!