ST表 ----kzsn考挂后有感

ST表,一个十分神奇的东西,需要O(nlogn)的时间预处理,但是他查询只需要O(1)。

看似与线段树等数据结构时间复杂度一样,但是ST表的复杂度只在于预处理,预处理之后可以当做不耗时!

而想线段树这种东西,查询是O(logn)的,一旦与其他复杂度乘在一起,就会发现TLE离你不远了!

面对不会修改数据的题,ST表妥妥的第一选择!

好了,现在开始补kzsn一直没学完全明白的ST表!

 

ST表主要支持不修改的区间的查询,运用了倍增的思想。

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define LL long long

const int N=2e6+6;

int lg[N], f[N][23];//用多少,开多少,kzsn心里记住了 
signed main()
{
    int n, m;scanf("%d%d",&n,&m);
    for(re i=1;i<=n;++i)
    {
        scanf("%d",&f[i][0]);
        if(i>1) lg[i]=lg[i>>1]+1; // 预处理 log2
    }
    // f[i][j] 记录了区间 [j, j+(1<<i)-1]的区间最值 
    // 值得注意的是,ST表以及其他倍增的东西,倍增的大小一定要放数组第一位,这样更快。 
    for(re i=1; i<=20; ++i) // 枚举倍增区间 
    {
        for(re j=1; j+(1<<i)-1 <= n; ++j) // 区间起点 
        {
            f[j][i] = max(f[j][i-1], f[j+(1<<(i-1))][i-1]); 
            // 这里求区间 [j, j+(1<<i)-1]的区间最值
            // 可以转化成区间 [j, j+(1<<i-1)-1] 以及区间 [j+(1<<i-1), j+(1<<i)-1]
            // 千万注意这里的各种减1,kzsn就是这里不太搞得懂! 
        }
    }
    while(m--)
    {
        int l, r;
        scanf("%d%d",&l,&r);
        int s = lg[r-l+1];
        // 查询区间[l,r],变成查询两个区间
        // [l,l+(1<<s)-1] [r-(1<<s)+1, r],两区间重叠的部分对于答案没有影响的!! 
        printf("%d\n", max(f[l][s], f[r-(1<<s)+1][s]));
    }
    return 0;
}

希望以后kzsn不要再忘记ST表了!!!

posted @ 2021-10-13 20:23  kzsn  阅读(158)  评论(0编辑  收藏  举报