倍增方法应用——RMQ问题ST表

//蒟蒻

RMQ问题:给定一个长度为n的序列A[1…n],有q次询问,每次询问给出x,y,回答A[x…y]中的最大值(或最小值),n,q<=100000

用倍增解决RMQ问题的算法:ST(Sparse Table)算法

一般RMQ问题的ST算法

   对于序列A[1…n],我们构造一个二维数组st[1…n][0…logN^2],st[i][j]表示从i这个位置开始,向后2^j个位置(包括i)中的最大值,即Max{A[i…i+2^j-1]}。

如何构造ST表:

   构造数组B,是的B[i,j]表示A[i…i+2^j-1]中最小数的下标。(时间:O(NlogN^2)。然后对于每对i,j,令k=[log^2(j-i+1)],比较A[B[i,k]]与A[B[j-2^k+1,k]]的大小。

 显然st[i][0]=A[i]。除此之外,任何一个st[i][j]所表示的区间长度都是2的整数次方,即2j.将该区间从中间划分为两段,各长2j-1,则两段区间的起点分别为i和i+2j-1

于是可以得出

for(int i=1;i<=n;i++) st[i][0]=A[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);

时间复杂度n log n

构造完ST表后怎么办呢?

对于每次询问给出的x,y,其长度len=y-x+1

我们先找到最大的且小于等于len的2的整数次幂,例如2k

那么[x…y]这个区间的前2k和后2k个位置合起来完全可以覆盖该区间

于是Max{A[x…y]}=max(st[x][k],st[y-(1<<k)+1][k])

k=(int)(log(y-x+1)/log(2))

int query(int x,int y)
{
  int k=(int)(log(y-x+1)/log(2));
int m=max(st[x][k],st[y-(1<<k)+1][k]);
return m;
}
时间复杂度O(1)

 

posted @ 2022-09-11 15:23  为么要取名字  阅读(59)  评论(0编辑  收藏  举报