码迷,mamicode.com
首页 > 其他好文 > 详细

ST表

时间:2019-01-20 15:56:59      阅读:526      评论:0      收藏:0      [点我收藏+]

标签:scan   int   问题   现在   左移   最大   end   为什么   []   

st表--目的是解决RMQ问题(多次询问区间最值)

既然叫‘表’,那肯定要打个表,然后你问什么,我就在表里找就可以了,这样,询问时的时间复杂度就是O(n)。

妈妈再也不用担心我会超时了


设你把一个需要处理的序列存储在a [ i ] 中

s tiao表,首先要声明一个二维数组jump[i][j] or tiao[i][j] 来存储序列的最值(这里以最大值为例)


然后,定义(你心里明白就好)

jump[ i ][ j ] 表示区间 [ i , i + (2 ^ j) - 1 ] 的最值

不要问为什么,后面你会明白的。


然后把 jump[ i ][ j ]分开

jump[ i ][ j ] = max( jump [ i ][ j-1 ] , jump[ i + ( 2 ^ (j-1) ][ j - 1 ] )


max中前者为 [ i , i + ( 2 ^ (j-1) ) - 1 ]

后者为 [ i + ( 2 ^ (j-1) , i + ( 2 ^ j ) ]

刚好把 jump[ i ][ j ] 分开。所以最大值一定在其中。


jump[ i ][ 0 ]max = a[ i ]这是显然的,

所以就不需要前文中提到的 a [ i ] 了。

我们可以直接把数字序列存储到 jump[ i ][ 0 ] 中。

然后根据

jump[ i ][ j ] = max( jump [ i ][ j-1 ] , jump[ i + ( 2 ^ (j-1) ][ j - 1 ] )

把表打出来



对于一个要询问的区间[ x , y ]

找一个 k ,使得 k <= y - x + 1 < 2 * k

这里我们取 k = log2( y - x + 1 )

那么,我们就把区间 [ x , y ] 的最大值就表示为

max( jump[ x ][ k ] , jump[ y - ( ( 2 ^ k ) -1 ) ][ k ] )

其实就是区间 [ x , x + ( 2 ^ k ) - 1 ]

和区间 [ y - ( ( 2 ^ k ) - 1 ) , y ]

x + ( 2 ^ k ) - 1 是大于等于 y - ( ( 2 ^ k ) - 1 ) 的

及两个区间相交,那么[ x , y ] 的最大值就一定在这两个区间之中。




先把题链过来

P3865 【模板】ST表


接下来是代码

//This is Tao‘s program;

#include<bits/stdc++.h>
using namespace std;


//返回一个最大值 
int max(int x,int y)                    
{
    if(x>y) return x;
    return y;
}


//存储 st 表的数组 
int jump[500004][20];


int main()
{
    //l,r为稍候询问时输入的查询的区间[l,r]
    //k为log2(r-l+1),取的是一个‘中间‘的值 
    int n(0),m(0),l(0),r(0),k(0);


     //输入数列长度n,询问的个数m 
    scanf("%d%d",&n,&m);             


    //输入数列,存储至 jump[i][0]中 
    for(int i = 0;i<n;++i)
        {
            scanf("%d",&jump[i][0]);
        }


    //打st表,存储至 jump[][] 数组中
    //jump[i][j] 表示区间 [i , i+(2^j)-1]
    //1<<j就表示 2^j 
    for(int j = 1;j<=20;++j)
        {
            for(int i = 0;i+(1<<j)-1<n;++i)
                {
                    jump[i][j] = max(jump[i][j-1],jump[i+(1<<(j-1))][j-1]);
                }
        }


    //现在开始RMQ 
    for(int i = 1;i<=m;++i)
        {
            scanf("%d%d",&l,&r);

            --l;--r;  //由于之前打的表是从 jump[0][0] 开始的,而读入时是从1开始的 
                      //故整个往左移1位 

            k = log2(r-l+1);//取一个‘中间值‘k 

            //区间 [l , l+(2^k)-1]和[r-((2^k)-1) , r]有相交部分
            //故最大值必定在这两个区间之中 
            int s = max(jump[l][k],jump[r-(1<<k)+1][k]);

            printf("%d\n",s); //输出s 
        }


    return 0;
}

end

ST表

标签:scan   int   问题   现在   左移   最大   end   为什么   []   

原文地址:https://www.cnblogs.com/taorex/p/10294922.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!