倍增方法应用——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));时间复杂度O(1)
int m=max(st[x][k],st[y-(1<<k)+1][k]);
return m;
}
标签:RMQ,log,int,max,st,ST,倍增 来源: https://www.cnblogs.com/xdzxlsy/p/16683974.html