洛谷_3865 ST表

题意

给出一个序列,求某一个区间的最大值。(RMQ)

思路

ST算法,设 f[i][j] f [ i ] [ j ] 表示从序列的第 i i 个位置开始aj个数的最大值,我们可以得到公式 f[i][j]=max(f[i][j1],f[i+2j1][j1]) f [ i ] [ j ] = m a x ( f [ i ] [ j − 1 ] , f [ i + 2 j − 1 ] [ j − 1 ] ) ,相当于把一个从 i i 2j的区间分成了两个长度为 2j1 2 j − 1 的区间。当我们查询最大值的时候,我们可以算出一个 k k ,就是让2k<这个区间长度时, k k 的最大值,那么我们查询的区间(l,r)的答案就为 max(f[l][k],f[r2k+1][k]) m a x ( f [ l ] [ k ] , f [ r − 2 k + 1 ] [ k ] ) ,这两段刚好覆盖了这个区间,所以答案是准确的。

代码

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,x,y,f[100001][22];
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)scanf("%d",&f[i][0]);//初始化,因为从第i个数开始长度为1的区间的最大值就是它本身
    for(int j=1;j<=20;j++)
     for(int i=1;i+(1<<j)-1<=n;i++)
      f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    while(m--)  
    {
        scanf("%d%d",&x,&y);
        int k=log2(y-x+1);
        printf("%d\n",max(f[x][k],f[y-(1<<k)+1][k]));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值