Sparse Table ST表


贴一发上官松柏大犇写的博客。


ST表(Sparse Table)是能够区间查询最值的数据结构,它采用倍增与dp的思想进行维护。

ST表复杂度:

  • 空间复杂度 O(nlogn)
  • 预处理时间复杂度 O(nlogn)
  • 查询时间复杂度 O(1)

ST表优势:

  • ST表的价值在于用较大的空间复杂度换取的 O(1) 的查询复杂度,与线段树 O(n) O(n) O(logn) 不同,ST表的查询部分并入主要部分程序后整体复杂度不会比线段树高。所以是对程序效率的有效优化。

ST表劣势:

  • O(nlogn) 的较大空间复杂度。
  • 更新操作比较困难(即一般不支持更新,只能静态查询)。

预处理操作:

如果我们把每个k值当做一层,我们要考虑如何把 f[k][i] 用上一层的数据更新覆盖。采用倍增的思想,我们定义:

  • f[k][i] 表示区间 [i,i+2k1] (持续 2k 个)的最值。

显然上一层的覆盖范围正好是 f[k][i] 的一半,即 2k1 。那么我们就可以用两段刚好覆盖住的区间 [i,2k11] [i+2k1,(i+2k1)+2k11] 来收集结果了:

  • f[k][i]=min{f[k1][i],f[k1][i+2k1]}

查询操作:

同理,我们需要两个已知的固定区间,能够覆盖(可以重合一部分)整个查询区间。为了方便查找,我们规定这两个已知区间覆盖的区间长度均为2^k,并且两个区间分别有一端为L和R。那么随着这个k不断增大,一定存在一个临界点k,刚好覆盖(或最少重合)这个区间。

当k满足题意时,两个区间分别为 [L,L+2k1] [R(2k1),R] ,此时只需要满足 R(2k1)L+2k1 即可,化简之后推出公式:

  • RL+22k+1klog2(RL+2)1

小常数优化:

由于系统计算log非常慢,所以我们可以参考这篇文章 2i 的处理方法,把所有数值的log2()全部打表出来。这里的时间复杂度只需要 O(n)

int f[S][M],Log2[M],a[M];

void init(int n){//ST表的预处理
    int s=0;
    for(int i=1;i<=n;i++){
        f[0][i]=a[i];
        if(i&(i-1))Log2[i]=s;//删除最后一位二进制,如果刚好i=1<<t则变成0
        else Log2[i]=s++;
    }
    for(int k=1;(1<<k)<=n;k++)
        for(int i=1;i+(1<<k)-1<=n;i++)
            f[k][i]=min(f[k-1][i],f[k-1][(1<<k-1)+i]);
}

int query(int L,int R){//ST表的查询
    int k=Log2[R-L+2]-1;
    return min(f[k][L],f[k][R-(1<<k)+1]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值