ST表预处理复杂度O(nlogn),查询为ST表为O(1),st表的主体是一个二维数组st[i][j],采用的是dp(动态规划)的思想,i表示从位置i开始长度为2^j次幂的一个区间(即往右移动2^j-1个单位)。求一个区间的MAX以及MIN。
先看预处理的代码:这边写的是一个MIN,同理找区间最大即就是MAX
状态转移方程:st[i][j] = min (st [i] [j - 1],st [i + 2^(j - 1)] [j - 1]):即i+2^(j-1)----i+2^(j-1)+2^(j-1)比较
int a[1000];//原始输入数组
int st[1000][20];//st表
void init(int n)
{
int i,j;
for (i=0;i<n;i++)
st[i][0] = a[i];//将第一位赋值
for (j=1;(1<<j)<=n;j++)
{
for (i=0;i+(1<<j)<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
接下来就是查询函数,作为查询一段区间的MAX或者MIN;
int solvemin(int l,int r)//查询l---r的区间MIN
{
int k=log2(r-l+1);
return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}
不妨反向推导一下,(int) k=log2(r-l+1)由此可知 2^k<=(r-l+1)
并且2^k+l的肯定超过了(l+r)/2;
所以l到r的最小值可以表示为min(从l往后2^t的最小值,从r往前2^t的最小值)
带一道例题:
题目来源:http://poj.org/problem?id=3264 POJ 3264
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int a[50010];
int stmax[50010][20];
int stmin[50010][20];
void init(int n)
{
int i,j,k;
for(i=1;i<=n;i++)
stmax[i][0]=stmin[i][0]=a[i];
int t=log2(n)+1;
for(int j=1;j<t;j++)
{
for(int i=1;i<=n-(1<<j)+1;i++)
{
stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
}
}
}
int solvemax(int l,int r)
{
int k=log2(r-l+1);
return max(stmax[l][k],stmax[r-(1<<k)+1][k]);
}
int solvemin(int l,int r)
{
int k=log2(r-l+1);
return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}
int main()
{
int n,q,i,j;
scanf("%d %d",&n,&q);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
init(n);
while(q--)
{
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",solvemax(l,r)-solvemin(l,r));
}
return 0;
}