zoukankan      html  css  js  c++  java
  • 浅谈ST表

    原题是P3865

    传送门

    ST表是一种数据结构

    ST表类似于树状数组和线段数的数据结构,能够快速访问一定区间内的最大值/最小值的值(解决RMQ问题:Range Minimum/Maximum Query,即区间最值查询)问题的离线算法。

    其预处理的时间复杂度与线段树,树状数组相同,为O(n*logn)。

    但ST表查询的时间复杂度为O(1),而线段树和树状数组查询的时间复杂度都为O(logn)。是不是更加优秀了呢!

    首先我们来表示一下(以储存最大值为例):

    void do_it(){
        for(int i=1;i<=n;i++) st[i][0]=a[i];
        for(int i=1;(1<<i)<=n;i++){
            for(int j=1;j+(1<<i)-1<=n;j++){
                st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
            }
        }
        return ;
    }

    首先我们需要说明一下,st[i][j]的意义表示从i开始向右数pow(2,j)位中的最大值

    由于我们在内层循环中有判断j+(1<<i)-1<=n条件,所以一定会有i+pow(2,j)-1<=n

    所以我们很容易得到st[i][j]一定是合法的范围内的

    然后我们需要证明一个很简单的定理:

    当我们将log2x向下取整时,有2log2 >x/2    ①

    来证明一下:

    因为我们将log2x向下取整,假定x==pow(2,n),则log2x==n

    所以我们有当pow(2,n)<= x < pow(2,n+1)时的log2x均为n

    所以就有2log2 == pow(2,n),因为易得有pow(2,n)>pow(2,n+1)/2

    因为x<pow(2,n+1)

    所以有2log2> x/2

    QED.

    然后我们现在还要考虑如何求得向下取整的log2x 这一问题

    1.通过对数运算法则logab==logxb/logxa,以及调用cmath库中的log函数实现

    x=log(b)/log(a)
    (x是我们要求的logab)

    优点:方便

    缺点:当查询的次数很多时,很有可能使得时间复杂度大大增加

    2.预处理得到范围内的所有logn

    优点:访问方便且访问的时间复杂度为O(1)

    缺点:访问次数很少是预处理会增加很大的时间复杂度

    但是我们知道预处理的时间复杂度其实也是O(1)的,只不过只是一个很大的常数罢了,只要在范围内就不会TLE

    那么我们如何范围内一定范围内的最大值呢?

    假设我们要求i到x的最大值

    因为我们已经有定理①,所以当我们要求i到i+pow(2,j)-1范围内的最大值时,我们只需要求i到i+pow(2,j-1)-1的最大值和x-pow(2,j-1)+1到x范围内的最大值并且取两者中的较大值就可以了!

    AC代码:

    #include<cctype>
    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N = 100010;
    int lg[N];
    int n,m;
    int a[N];
    int st[N][20];
    int l,r;
    int read()
    {
        int x = 1,a = 0;
        char ch = getchar();
        while(ch < '0' || ch > '9'){//如果读进来的不是数字……
            if(ch == '-')x = -1;//判断负号
            ch = getchar();
        }
        while(ch <= '9'&&ch >= '0'){//如果读进来的是数字……
            a = a * 10 + ch - '0';
            ch = getchar();
        }
        return x*a;
    }
    void init(){
        lg[1]=0;
        for(int i=2;i<=n;i++){
            lg[i]=lg[i/2]+1;
        }
        return ;
    }
    void do_it(){
        for(int i=1;i<=n;i++) st[i][0]=a[i];
        for(int i=1;(1<<i)<=n;i++){
            for(int j=1;j+(1<<i)-1<=n;j++){
                st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
            }
        }
        return ;
    }
    int main(){
        n=read();
        m=read();
        for(int i=1;i<=n;i++){
            a[i]=read();
        }
        init();
        do_it();
        for(int i=1;i<=m;i++){
            l=read();
            r=read();
            printf("%d
    ",max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]));
        }
        return 0;
    }
  • 相关阅读:
    Use Study Groups to Support Learning
    “开闭”原则(OpenClosed principle, OCP)
    我的E72i 开发
    conlution of daily work
    appstore相关查询链接
    sqlite3.0不支持的sql属性
    iOS sdk 运行时函数
    自动化测试部分
    ios下获取mac地址修正版
    修改mac os host
  • 原文地址:https://www.cnblogs.com/robertspot/p/13689696.html
Copyright © 2011-2022 走看看