RMQ __ST
Posted qimang-311
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RMQ __ST相关的知识,希望对你有一定的参考价值。
迅哥讲解(说实话没有认真听,不过关系不大)
RMQ:Range Minimum Maximum Query 给定一个序列A[1…N],问A[i…j]之间的极值 如果只问一次,
显然是O(N) 标准RMQ问题是:不停的查询同一个序列上的不同区间内的极值
序列A的长度N,一共Q次查询 纯暴力法:O(NQ) 带预处理的暴力法: 矩阵B[N][N],
令B[i][j]是A[i…j]的极值 求B需要一个双重循环,O(N2) 对每一次查询只需O(1)即可
所以总时间复杂度O(N2+Q) 空间复杂度则为O(N2)
Sparse Table算法
矩阵M[N][logN+1] M[i][j]是区间A[i, i+2j)的极值 矩阵M的元素值的确定:
类似于倍增算法
本题采用的倍增的思路 (说实话感觉像个dp)
首先令M[i][j]代表从i开始长度为2^j的数列 中的极值(左闭右开的区间)
由此图可知 找寻极值之时只要查找左右两个区间就行了(有点二分的意味)
所以输入的原始值就是M[i][0] 而每一次找寻的过程中就是M[i][j]=极值(M[i][j-1],M[i+2^(j-1)][j-1]) 只要从2^j开始例举,
但是注意因为i是从1开始,而最少j=1,所以i的值小于等与n-1,并非n。
拿迅哥原图说话
给定两个下标l,r进行查询,我的k是从0开始的,所以相等时也要再+1,
查找从i开始长度为2^k和从r-2^k+1长度为2^k;
只不过可以直接求取( k = (int)( log((double)(r-l+1)) / log(2.0) );)
贴代码
#define ll int using namespace std; const int maxn=1e5+7; int n; int M[maxn][1050]; void st_RMQ() { for (int j=1;(1<<j)<=n;++j) for (int i=0;i+(1<<j)-1<=n;++i) M[i][j]=max(M[i][j-1],M[i+(1<<(j-1))][j-1]); } int RMQ(int l,int r) { int k=0; while ((1<<(k+1))<=r-l+1) ++k; return max(M[l][k],M[r-(1<<k)+1][k]); } int main() { int t; cin>>n>>t; for (int i=1;i<=n;++i) cin>>M[i][0];///以i开头长度为1中的最大值 st_RMQ(); int x,y; while(t--) { scanf("%d%d",&x,&y); printf("%d ",RMQ(x,y)); } return 0; }
以上是关于RMQ __ST的主要内容,如果未能解决你的问题,请参考以下文章