简要理解ST表

  ST表

  • 注:ST表需要用到倍增算法;ST表实质上是一种DP

ST表的作用

  • 快速查询区间最大值和区间最小值

前提:倍增

  • 我们读入了一个长度为n的数列,用a[1]~a[n]存储。然后我们不由分说地先算出数列中第1~n-1个数的 后两个数(包括它自身)中的最大值,比如说,第一个数后两个数的最大值=max(a[1],a[2])。a[n+1]不存在,所以
    不用计算a[n]后两个数的最大值,计算到a[n-1]就可以(而且必须)停下来了

  • 然后我们再算出数列中第1~n-3个数的 后四个数(包括它自身)中的最大值,可以再枚举一遍,但我们有先前算好的结果可以利用:第一个数后四个数的最大值=max(第一个数后两个数的最大值,第三个数后两个数的最大值)

1599106-20190215141855365-588002133.jpg

  • 依次类推,第一个数后八个数的最大值=max(第一个数后四个数的最大值,第五个数后四个数的最大值),第一个数后十六个数的最大值=max(第一个数后八个数的最大值,第九个数后八个数的最大值),……

正题:ST表

  • 定义一个数组st[n][x]存储这些值,st[i][j]表示第i个数后面的2^j(即1<<j)个数(包括第i个数自身)中的最大值,x可以用符合2^x<=n的最大x值(+10防越界),也可以自己定义一个足够用的值(+10防越界)
  • st[i][0] 即为 a[i],可以用 st[i][0] 代替 a[i] 存储数列
for(int j = 1;j <= x; ++j ){
    for(int i = 1;i <= n - (1<<j) +1 ; ++ i){
        st[i][j] = std::max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    }
}

1599106-20190215142005555-1843439459.jpg

解释

  • j的循环在最外面

根据转移方程 st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1])(i<=n-2^j+1,1<=j<=x),只有算出所有的st[i][j-1],才能计算st[i][j]。

  • i<=n-(1<<j)+1

计算a[i]到a[j]之间的最大值,防止越界,最多只能枚举到a[i]~a[n],
此时n-i+1=2^j(即1<<j),i=n-2^j+1,所以1<=i<=n-(1<<j)+1。

使用

  • 不断分割查询区间,直到剩下的区间长度为0,并把所有分割数的区间对应的最大值 一 一比较
  • j从x向1枚举,直到(1<<j)<=区间长度,分割并结束循环,即每次只分割 大于区间长度的一半小于等于区间长度 的一段
int search(int l,int len,int r)
{
    if(l>r) return -0x3f3f3f3f;
    if(len<=0) return -0x3f3f3f3f;
    for(int i=25;i>=0;--i){
        if( (1<<i) <=len )
            return std::max(t[l][i],search(l+(1<<i),len-(1<<i),r));
    }
}

拓展

  • 最小值当然也可以,注意search查询越界返回的极小值换成极大值就行

转载于:https://www.cnblogs.com/StarOnTheWay/p/10383448.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值