算法笔记——ST表

ST表

ST表是一种简单的数据结构,主要用于解决RMQ问题(区间最大/最小值问题)主要应用倍增的思想,可以实现O(nlogn)预处理,O(1)查询

1.预处理ST表

倍增法递推:用两个等长的小区间拼凑一个大区间
f[i][j]表示以第i个数为起点,长度为2^j的区间里的最大值/最小值
f[i][j]=max(f[i][j-1],f[i+2^j-1][j-1])
区间终点:i+2^j-1 <= n

代码实现

for(int i=1;i<=n;i++)
    cin>>f[i][0];
for(int j=1;j<=20;j++)//先枚举区间长度的指数
{
    for(int i=1;i+(1<<j)-1<=n;i++)//枚举起点  i+(1<<j)-1是区间的终点要受到上界n的限制
    {
        f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);//在这段代码中所举的例子是最大值,改成min(,)就是最小值,改成gcd()就是最大公约数。。类似
    }
}

对于此算法外层时间复杂度是O(logn),内层是O(n)的,总的时间复杂度就是O(nlogn)的

比如 n=6;

f[i][0]: f[1][1] f[2][2] f[3][3] f[4][4] f[5][5] f[6][6]
f[i][1]: f[1][2] f[2][3] f[3][4] f[4][5] f[5][6] 
f[i][2]: f[1][4] f[2][5] f[3][6]
if j==3:i+2^j-1=1+8-1= 8 > 6

2.处理询问

对查询区间 [l,r]做分割,拼凑,
区间长度的指数 k=log2(r-l+1) (注意:这一运算是下取整的)
我们列出所有的情况:

        //区间长度可能的情况
k = 0: {1}
k = 1: {2,3}
k = 2: {4,5,6,7}
k = 3: {8,9,10,...,15}

由此:2^k <= r-l+1 < 2*2^k,即 区间 [l,r]必可以用两个长度为2^k的区间来 重叠拼凑 出来!

代码实现

while(T--)
{
  int l,r;
  cin>>l>>r;
  int k=log2(r-l+1);
  cout<<max(f[l][k],f[r - (1<<k) + 1][k])<<endl;
}

3.拓展

ST表不仅能够解决 RMQ问题,更可以解决所有符合结合律且可重复贡献的信息查询都可以使用ST表高效进行。
可重复贡献:设有一个二元运算f(x,y) 满足 f(a,a) = a,则运算f是可重复贡献的,显然最大值,最小值,最大公约数,按位或,按位与都符合这个条件。
可重复贡献的意义在于,可以对两个交集不为空的区间进行信息合并。

例题:

洛谷:P2880 [USACO07JAN] Balanced Lineup G

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int maxx[N][21];
int minn[N][21];//注意第二位代表的数字是j是区间长度的log因此不需要开太大

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin>>maxx[i][0];
        minn[i][0]=maxx[i][0];
    }
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);
            minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
        }
    }
    int l,r;
    while(q--)
    {
        cin>>l>>r;
        int k=log2(r-l+1);
        cout<<max(maxx[l][k],maxx[r - (1<<k) + 1][k])-min(minn[l][k],minn[r - (1<<k) + 1][k])<<endl;
    }
    return 0;
}
posted @ 2023-08-02 16:27  liuwansi  阅读(37)  评论(0编辑  收藏  举报