ST算法(Sparse Table):它是一种动态规划的方法。
以最小值为例。a为所寻找的数组.
用一个二维数组f(i,j)记录区间[i,i+2^j-1](持续2^j个)区间中的最小值。其中f[i,0] = a[i];
所以,对于任意的一组(i,j),f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)}来使用动态规划计算出来。
这个算法的高明之处不是在于这个动态规划的建立,而是它的查询:它的查询效率是O(1).
假设我们要求区间[m,n]中a的最小值,找到一个数k使得2^k<n-m+1.
这样,可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n].我们发现,这两个区间是已经初始化好的.
前面的区间是f(m,k),后面的区间是f(n-2^k+1,k).
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define M 50005
int mx[M][16],mi[M][16];
int a[M];
void rmqinit(int n)
{
for(int i=1;i<=n;i++)
{
mx[i][0]=mi[i][0]=a[i];
}
int i,j;
for(j=1;1<<j<=n;j++) //here:Why j is in front of i ??
{
for(i=1;i+(1<<j)-1<=n;i++)
{
int t=(1<<(j-1))+i;
mx[i][j]=max(mx[i][j-1],mx[t][j-1]);
mi[i][j]=min(mi[i][j-1],mi[t][j-1]);
}
}
}
int qmx(int l,int r)
{
int k=(int)( log((r-l+1)*1.0) / log(2.0));
return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int qmi(int l,int r)
{
int k=(int)( log((r-l+1)*1.0) / log(2.0));
return min(mi[l][k],mi[r-(1<<k)+1][k]);
}
int main()
{
int n,q,l,r;
while(~scanf("%d%d",&n,&q))
{
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
rmqinit(n);
while(q--)
{
scanf("%d%d",&l,&r);
printf("%d\n",qmx(l,r)-qmi(l,r));
}
}
}
以最小值为例。a为所寻找的数组.
用一个二维数组f(i,j)记录区间[i,i+2^j-1](持续2^j个)区间中的最小值。其中f[i,0] = a[i];
所以,对于任意的一组(i,j),f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)}来使用动态规划计算出来。
这个算法的高明之处不是在于这个动态规划的建立,而是它的查询:它的查询效率是O(1).
假设我们要求区间[m,n]中a的最小值,找到一个数k使得2^k<n-m+1.
这样,可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n].我们发现,这两个区间是已经初始化好的.
前面的区间是f(m,k),后面的区间是f(n-2^k+1,k).
这样,只要看这两个区间的最小值,就可以知道整个区间的最小值!
poj 3264
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define M 50005
int mx[M][16],mi[M][16];
int a[M];
void rmqinit(int n)
{
for(int i=1;i<=n;i++)
{
mx[i][0]=mi[i][0]=a[i];
}
int i,j;
for(j=1;1<<j<=n;j++) //here:Why j is in front of i ??
{
for(i=1;i+(1<<j)-1<=n;i++)
{
int t=(1<<(j-1))+i;
mx[i][j]=max(mx[i][j-1],mx[t][j-1]);
mi[i][j]=min(mi[i][j-1],mi[t][j-1]);
}
}
}
int qmx(int l,int r)
{
int k=(int)( log((r-l+1)*1.0) / log(2.0));
return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int qmi(int l,int r)
{
int k=(int)( log((r-l+1)*1.0) / log(2.0));
return min(mi[l][k],mi[r-(1<<k)+1][k]);
}
int main()
{
int n,q,l,r;
while(~scanf("%d%d",&n,&q))
{
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
rmqinit(n);
while(q--)
{
scanf("%d%d",&l,&r);
printf("%d\n",qmx(l,r)-qmi(l,r));
}
}
}