ST表 x RMQ问题

RMQ问题,即区间最值问题
tarjan发明的基于倍增的st表算法
可以在 O ( n l o g n ) O(nlogn) O(nlogn)的时间内求解静态RMQ问题

d p [ i ] [ j ] dp[i][j] dp[i][j]表示序列区 [ i , i + 2 j ] [i,i+2^j] [i,i+2j]内的最值
初始化 d p [ i ] [ 0 ] = a [ i ] dp[i][0]=a[i] dp[i][0]=a[i]

那么dp数组就有递推式
d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i + ( 1 &lt; &lt; j − 1 ) ] [ j − 1 ] ) dp[i][j]=max(dp[i][j-1],dp[i+(1&lt;&lt;j-1)][j-1]) dp[i][j]=max(dp[i][j1],dp[i+(1<<j1)][j1])
即区间 [ i , i + 2 j ] [i,i+2^j] [i,i+2j]中的最值等于区间 [ i , i + 2 j − 1 ] [i,i+2^{j-1}] [i,i+2j1] [ i + 2 j − 1 , j ] [i+2^{j-1},j] [i+2j1,j]中的最值

for(int i=1;i<=n;i++)
dp[i][0]=a[i];

for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);

当我们查询区间 [ l l , r r ] [ll,rr] [ll,rr]中的最值时
可以枚举一个断点k
比较区间 [ l l , l l + 2 k ] [ll,ll+2^k] [ll,ll+2k] [ r r − 2 k + 1 , r r ] [rr-2^k+1,rr] [rr2k+1,rr]得到答案

int k=0;
while((1<<k+1)<=rr-ll+1)k++;
ans=max(dp[ll][k],dp[rr-(1<<k)+1][k]);

虽然两个区间可能会重叠,但是这并不影响结果,因为重叠部分也属于 [ l l , r r ] [ll,rr] [ll,rr]
这也是用于比较的第二个区间是 [ r r − 2 k + 1 , r r ] [rr-2^k+1,rr] [rr2k+1,rr]的原因
如果第二个区间是 [ l l + 2 k , l l + 2 k + 2 k ] [ll+2^k,ll+2^k+2^k] [ll+2k,ll+2k+2k]将有可能越出rr的边界


洛谷P3865 【模板】ST表

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;

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

void print(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int n,m;
int d[1000010];
int dp[1000010][55];

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    d[i]=read();
    
    for(int i=1;i<=n;i++)
    dp[i][0]=d[i];
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i+(1<<j)-1<=n;i++)
    dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
    
    while(m--)
    {
        int ll=read(),rr=read();
        int k=0;
        while((1<<k+1)<=rr-ll+1)k++;
        int ans=max(dp[ll][k],dp[rr-(1<<k)+1][k]);
        print(ans);printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值