首页 > 其他 > 详细

ST表

时间:2021-02-17 13:40:32      阅读:23      评论:0      收藏:0      [点我收藏+]

给一个数列,巨多次询问区间最值,窝萌用ST表解决多次查询不修改问题。这篇以左闭右闭区间为例。

 

st [ i ] [ j ] 表示从第 i 位开始 ( 包括第 i 位 ) ,2 ^ j 个数中的最值。

 

显然,st [ i ] [ 0 ] = n [ i ]         st [ i ] [ j ] = max ( st [ i ] [ j - 1 ] , st [ i + 2^( j - 1) ] [ j - 1 ] ) 

 

在预处理时,由于需要用到st [ i + 2^( j - 1) ] [ j - 1 ],必须把 j 作为外层循环,否则st [ i + 2^( j - 1) ] [ j - 1 ]全是0。

 

预处理好了之后,窝萌就可以 O ( 1 ) 地查询区间最值 (rmq) 了。

 

我们发现这样一个性质 : max ( L ~ R )  =  max ( max( L ~ i ) , max( j ~ R ) )  ( L ≤ j ≤ i ≤ R )

 

利用窝萌预处理好的st表,取 m = log2 ( R - L + 1 ),易知max ( L ~ R )  =  max ( st [ L ] [ m ]  , st [ R - 2^m + 1] [ m ] ) (开篇说明是左闭右闭区间,其他情况注意边界+1-1即可)

技术分享图片
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n[100005];
int a;
int st[100005][25];            //st[i][j]表示从第 i项开始(包含第 i项),2^j 项中的最值 

void init()
{
    for(int i=1;i<=a;i++)
        st[i][0]=n[i];
    for(int j=1;j<=20;j++)                 //一定是表示 2^j 的循环在外层
                                            //1e5 ~ 2^17    1e6 ~ 2^20 
        for(int i=1;i+(1<<j)-1<=a;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
void find(int ll,int rr)
{
    int mid=log2(rr-ll+1);
    int ans=max(st[ll][mid],st[rr-(1<<mid)+1][mid]);
    printf("%d\n",ans);
}
int main()
{
    int m;
    scanf("%d%d",&a,&m);
    for(int i=1;i<=a;i++) scanf("%d",&n[i]);
    init();
    int l,r;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        find(l,r);
    }
    return 0;
}
st form

 

ST表

原文:https://www.cnblogs.com/nightfury/p/14408659.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!