The Water Problem(RMQ的ST写法)

ST算法:基于动态规划求区间最值的算法。

以O(nlogn)的预处理代价,换取O(1)的查询时性能,f[i,j]代表从第i个数起连续2^j个数中的最大值。把f[i,j]平均分成两段(因为f[i,j]一定是偶数个数字)从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1)),显然f[i , j] = max(f[i ,  j-1],f[ i + 2^(j-1),  j-1])。询问时只要求出一个最大的k使y - x + 1大于2^j即可将询问拆分成f[x][k]和f[y - (1<< j) + 1][k]。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int f[1050][1050],a[1050];
void st(int n){
    int k=log(n*1.0)/log(2);
    for(int j=1;j<=k;j++){
        for(int i=1;i<=n;i++){
            if(i+(1<<(j-1))>n){
                break;
            }
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
}
int sum(int a,int b){
    int k=log(b-a+1.0)/log(2);
    return max(f[a][k], f[b - (1<<k) + 1][k]);
}
int main(){
    int t,n,q;
    cin>>t;
    while(t--){
        memset(f,0,sizeof(f));
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    f[i][0]=a[i];
    }
    st(n);
    scanf("%d",&q);
    int a,b;
    for(int i=1;i<=q;i++){
        scanf("%d %d",&a,&b);
        printf("%d\n",sum(a,b));
    }
    }
}

猜你喜欢

转载自www.cnblogs.com/Yum20/p/9630775.html