ST表

来源:互联网 发布:话筒淘宝购买 编辑:程序博客网 时间:2024/05/17 07:01

st表用来维护静态区间最值非常有效快捷的方法,但是只要取最值的数需要改变,那么st表便变得无用,你需要转去研究下线段树了。那么下面来看看初看不好理解,但是超好写的st表模板求最大或最小值。
问题:给出长度为N的数组,存放于data[ ]数组中,每次询问区间最大值,没有修改。
空间上需要准备一个二维数组a[i][j]用以存储以i为起点的2^j个元素的最大值。如a[3][0]存储的就是以第3个元素为起点的2^0个元素的最大值,这个是就是data[3],那么a[3][3]存储的便是以第3个元素为起点的2^3个元素的最大值.
这里写图片描述
因此st表里初始化的时候,i为起点的2^j个元素的最大值便是由上图中蓝色和黄色两个部分中最值取最大值,这两部分起点分别是i和i+2^(j-1),因此便有如下的递推式:
a[i][j] = max(a[i][j-1],a[i+(1 << (j-1))][j-1]);
那么当所有的最大值记录到了a数组中后,下面便是查询最值了。假设查询的区间是[x,y],那么你需要找到那个k,让以x为起点的2^k个元素和以y为终点的2^k个元素的两个区间的叠加中的最大值。那么这个k的取值需要能让这样两个区间能重叠,如下图所示:
这里写图片描述
因此令k为满足2^k <= y - x +1的最大整数 ,查询[x ,y]的最值为
max(a[x][k],a[y-(1 << k)+1][k]).
上面便是对st表的初始化和查询的解释分析。下面上标程:

#include<iostream>#define MAXN 100010using namespace std;int n,m;int a[MAXN][18];int main(){    cin >> n >> m;    for(int i=1;i<= n; i++)    {        scanf("%d",&a[i][0]);    }    for(int j = 1;(1<<j) <= n; j++)  //st表初始化    {        for(int i = 1; i + (1<<j)-1 <=n; i++)        {            a[i][j] = max(a[i][j-1],a[i+(1<<(j-1))][j-1]);        }    }     int x,y,k;    for(int i = 1; i<= m; i++)//共m条询问    {        scanf("%d%d",&x,&y);        //查询操作,查询[x,y]范围内的最大值        k = 0;        while((1<< (k+1)) <= y - x + 1 )k++;        printf("%d\n",max(a[x][k],a[y-(1<<k)+1][k]));    }     return 0;}
原创粉丝点击