RMQ算法-建立ST表

RMQ算法思想:

一个高效的用于查询区间最大/最小值的方法,其需要O(nlogn)的时间复杂度进行预处理,之后对于每次的区间查询的复杂度为O(1)。

算法的预处理:

(1)采用DP的思想(也可以说分治法). 设dp[i][j]表示从i开始的连续 j 2 j^2 j2个数的最大值,显然初始值dp[i][0]=a[i], 而对于每个dp[i][j]可以划分为区间[i,i+2^j-1 +1] 和[i+2^j-1, i+2^j-1]则dp[i][j]=max(dp[i][j−1],dp[i+(1<<(j−1))][j−1])这样只要先枚举j的大小,然后再对每个i进行计算。
(2)创建一个Log2[N]的数组,利用换底公式和log函数,将其变为一个以2为底的log函数,方便后面区间查询,将区间长度k转为2的k次方。

查询:

对于我们要查询的区间[l,r],我们计算k=log 2 (r−l+1), 然后将其分成两成两个区间,则答案为dp[l][r]=max(dp[l][k],dp[r-(1<<k)+1][k])

算法例题:
题目描述:输入一串数字,给你 M 个询问,每次询问就给你两个数字 X,Y,要求你说出 X 到 Y 这段区间内的最大数。
输入格式:

第一行两个整数 N,M 表示数字的个数和要询问的次数;
接下来一行为 N 个数;
接下来 M 行,每行都有两个整数 X,Y。

输出格式:

输出共 M 行,每行输出一个数。

数据范围:

1≤N≤105,
1≤M≤106,
1≤X≤Y≤N,
数列中的数字均不超过231−1

输入样例:
10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8
输出样例:
5
8
C++代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int a[N];
int Log2[N];
int f[N][20];
void ST_RMQ()
{
    for(int i = 1;i<=n;i++) Log2[i] = log(i)/log(2);//换底公式,处理询问时区间的长度转换log2(k)
     for(int i=1;i<=n;i++)
          f[i][0]=a[i];  
           for(int j=1;(1<<j)<=n;j++) //表示区间长度为log2(n)
           {
                for(int i=1;i<=n-(1<<j)+1;i++)
             {
                f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
                  }
             }
}
int query(int l,int r) //区间查询
{
      int k=Log2[r-l+1];
      return max(f[l][k],f[r-(1<<k)+1][k]);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
       ST_RMQ();
     while(m--)
     { 
           int x,y;
           scanf("%d%d",&x,&y);
          printf("%d\n",query(x,y));
     }
     return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值