RMQ区间最值查询SparseTable算法

来源:互联网 发布:mac 便笺 保存位置 编辑:程序博客网 时间:2024/05/22 11:40
//一维区间最值查询模板稀疏表sparse table算法//区间最值查询--线段树--RMQ//区间连续和--线段树//区间第k大--快排--划分树(线段树?) --主席树 //二维区间最值查询根据一维区间最值查询的思想写代码 /*区间最值查询RMP  ST 算法 原理:  O(nlogn)预处理,O(1) 查询        预处理--使用动态规划,令F(i,j)表示以i起始的2^j长的子序列                F[i,0]即为原序列的每一个数,                有状态转移方程F(i, j ) = max(F(i,j-1), F(i+ (1<<(j-1)) , j-1 )        查询----对于i,j区间最值RMP(A,i,j)                 他的长度为 j-i+1                令k = log2( j - i + 1)                有i~j区间的最值max(F(i,k) , F[j- (1<<k) + 1 , k ) )复杂度  预处理 O(nlogn)        查询   O(1)应用    在线查询区间最值*/ #include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std ;const int maxn = 1e5 + 10 ;//F[i][j] 表示[i , i + ( 1<< j )- 1] 区间的最值 int F[maxn][20 + 1] ;void RMQ(int n ){    //j必须在外循环, 因为状态转移方程是从j-1 到j , 也就是说要计算j,即必须计算完j-1的所有数     //j代表区间长度1<<j,他指的是[i, i + ( 1<< j ) -1 ] 的区间的区间长度是 1<< j      for ( int j = 1 ; j<= 20 ;j ++)        //i代表区间起点i        //区间[ i , i+ (1<<j) -1 ] 的最值为两部分区间[i , i + (1<<(j-1)) -1 ] 和[ i + (1<<(j-1)) , i + ( 1<<j) -1] 的最值         // F[i,j] = max( F[i , j-1] , F[i + (1<<(j-1)) +1 , j-1])          for(int i = 1 ; i <= n ;i ++)            //保证第二个子区间下标在区间范围内             if( i + ( 1<<(j-1)) <= n )                F[i ] [j]= max( F[i][j-1] , F[i + (1<<(j-1))] [ j -1] ) ; }int query(int i , int j ){    //划分区间长度让结果为两部分子区间的比较值    //取子区间为前1<<k个数和后1<<k个数     int k = log10( j - i + 1.0) / log10 (2.0) ;    return max( F[i][ k ] , F[j - ( 1<<k ) + 1] [ k]) ;}int main(){    //n代表序列长度,m代表询问个数     int n , m ;    cin>>n>>m ;    for(int i = 1 ;i <= n ; i ++){        cin>>F[i][0] ;    }    RMP( n ) ;    while(m--){        int i , j ;        cin>>i >> j ;        int ans = query( i , j) ;        cout<<ans<<endl;    }    return 0 ;}