ST表浅谈

本文介绍了使用ST表解决区间最大值查询(RMQ)问题的方法。通过预处理得到核心数组st[i][j],实现O(1)时间复杂度的查询效率。文章详细解释了st表的构建过程及其查询原理,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片述世界真的很大

说来惭愧,直到昨天才搞清楚这个st表,然后花时间整理了一下思路,终于是差不多了。其实本来不想写的,网上看来看去好像st表除了RMQ,LCA就没什么了,况且LCA我会树链剖分,RMQ能写线段树,除了代码量少的那么一点点优势,我学他干嘛?后来一想,这种倍增的思想其实可能有点用,有可能在许多dp方程之类的能用得到,况且整体思想还很简单,就直接简单说明一下了。
以RMQ为例吧,介绍一下ST表。(这里就只管区间最大值了)
首先来见识一下ST表的核心数组st[i][j],意思是,由数列i位置往后推2^j个单位长度的区间里的最大值,然后呢,stmax的更新也就是dp的思想,st[i][j]可以由st[i][j-1],st[i+(1<<(j-1))][j-1]得到,因为2^(j-1)肯定是2^j的一半,相当于就是把一个区间的前后两部分的最大值相比较,得出这个区间的最大值,这是一个递推的关系。代码:

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

查询的时候便更简单,有了这个st表几乎无所不能,没错,o(1)查询。
记录查询区间为l,r。如果(r-l+1)正好是2^j,那么就直接返回st[l][j]就行了。但不可能每次查询的时候正好区间长度就是2的整数次幂,所以我们直接取区间长度的log值,向下取整,有可能并不能完全覆盖区间长度,但也绝对比区间的一半要长,(理解一下log),那么我们就可以把区间分成两个部分,长度都是2^(log(n)),因为只是取最值,所以两段可以重合一部分,代码:

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

这里是提前预处理了log值,从1到n,向下取整,log函数的预处理其实可以和st表的预处理结合到一起,好好理解下:

for(int i=1;i<=n;i++)
    {
        log[i]=((i&(i-1))==0)?log[i-1]+1:log[i-1];
        st[i][0]=a[i];
    }

这个log就是重点了。
完整代码:

#include<stdio.h>
#include<algorithm>
using namespace std;
int n=100,m,a[10010],st[10010][40],log[10010];
void init()
{
    log[0]=-1;
    for(int i=1;i<=n;i++)
    {
        log[i]=((i&(i-1))==0)?log[i-1]+1:log[i-1];
        st[i][0]=a[i];
    }
    for(int j=1;j<=log[n];j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

嗯,就是这样。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值