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)); } } }