【实现代码】
1 /* 2 pku3264 3 大意是给你一串数字,然后问你从第i个到第j个中最大的数减去最小的数的值 4 用rmq求出【i,j】中的最大最小值相减即可 5 rmq算法思想: 6 一,预处理 7 设a[i]是要求区间最值的数列,f[i,j]表示从第i个数起连续2^j个数中的最大值。 8 例如数列3 2 4 5 6 8 1 2 9 7 ,f[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。 9 f[1,2]=5,f[1,3]=8,f[2,0]=2,f[2,1]=4……从这里可以看出f[i,0]其实就等于a[i]。 10 这样,Dp的状态、初值都已经有了,剩下的就是状态转移方程。 11 我们把f[i,j]平均分成两段(因为f[i,j] 一定是偶数个数字), 12 从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。 13 用上例说明,当 i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。 14 f[i,j]就是这两段的最大值中的最大值。 15 于是我们得到了动规方程F[i,j]=max(F[i,j-1],F[i+2^(j-i),j-1]). 16 二,查询 17 如在上例中我们要求区间[2,8]的最大值,就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由f[2,2]和f[5,2]得到。扩展到一般情况,就是把区间[l,r]分成两个长度为2^k的区间(保证有f[i,j]对应)。直接给出表达式: 18 k:=trunc(ln(r-l+1)/ln(2)); 19 ans:=max(F[l,k],F[r-2^k+1,k]); 20 */ 21 #include <iostream> 22 #include <math.h> 23 #define max(a,b) ((a>b)?a:b) 24 #define min(a,b) (a<b?a:b) 25 26 using namespace std; 27 28 const int maxn=50001; 29 int h[maxn]; 30 int mx[maxn][16],mn[maxn][16]; 31 int n,q; 32 33 void rmq_init() 34 { 35 int i,j,t; 36 for(j=1;j<=n;j++) mx[j][0]=mn[j][0]=h[j]; 37 int m=floor(log((double)n)/log(2.0)); 38 for(i=1;i<=m;i++){ 39 for(j=1;j<=n;j++){ 40 t = j+(1<<(i-1)); 41 if(t<=n) mx[j][i]=max(mx[j][i-1],mx[t][i-1]); 42 else mx[j][i]=mx[j][i-1]; 43 } 44 } 45 for(i=1;i<=m;i++){ 46 for(j=1;j<=n;j++){ 47 t = j+(1<<(i-1)); 48 if(t<=n) mn[j][i]=min(mn[j][i-1],mn[t][i-1]); 49 else mn[j][i]=mn[j][i-1]; 50 } 51 } 52 } 53 54 int rmq(int l,int r) 55 { 56 int m=floor(log((double)(r-l+1))/log(2.0)); 57 int a=max(mx[l][m],mx[r-(1<<m)+1][m]); 58 int b=min(mn[l][m],mn[r-(1<<m)+1][m]); 59 return a-b; 60 } 61 62 int main() 63 { 64 int i,l,r; 65 scanf("%d%d",&n,&q); 66 for(i=1;i<=n;i++) scanf("%d",&h[i]); 67 rmq_init(); 68 for(i=0;i<q;i++){ 69 scanf("%d%d",&l,&r); 70 printf("%d\n",rmq(l,r)); 71 } 72 return 0; 73 }
【题目链接:NYOJ-1185】
如果C等于1,输出第L个数到第R个数之间的最小值;
如果C等于2,输出第L个数到第R个数之间的最大值;
如果C等于3,输出第L个数到第R个数之间的最小值与最大值的和。
2 4 1 3 2 4 2 1 1 4 2 2 3 5 1 2 3 4 5 1 3 1 5
1 3 6
1 2 #include <cstdio> 3 #include <math.h> 4 #define max(a,b) ((a>b)?a:b) 5 #define min(a,b) (a<b?a:b) 6 7 const int maxn=50001; 8 int h[maxn]; 9 int mx[maxn][16],mn[maxn][16]; 10 int n,q; 11 12 void rmq_init() 13 { 14 int i,j,t; 15 for(j=1;j<=n;j++) mx[j][0]=mn[j][0]=h[j]; 16 int m=floor(log((double)n)/log(2.0)); 17 for(i=1;i<=m;i++){ 18 for(j=1;j<=n;j++){ 19 t = j+(1<<(i-1)); 20 if(t<=n) mx[j][i]=max(mx[j][i-1],mx[t][i-1]); 21 else mx[j][i]=mx[j][i-1]; 22 } 23 } 24 for(i=1;i<=m;i++){ 25 for(j=1;j<=n;j++){ 26 t = j+(1<<(i-1)); 27 if(t<=n) mn[j][i]=min(mn[j][i-1],mn[t][i-1]); 28 else mn[j][i]=mn[j][i-1]; 29 } 30 } 31 } 32 int rmq(int l,int r) 33 { 34 int m=floor(log((double)(r-l+1))/log(2.0)); 35 int a=max(mx[l][m],mx[r-(1<<m)+1][m]); 36 int b=min(mn[l][m],mn[r-(1<<m)+1][m]); 37 return a+b; 38 } 39 int out_min(int l,int r){ 40 int m=floor(log((double)(r-l+1))/log(2.0)); 41 int b=min(mn[l][m],mn[r-(1<<m)+1][m]); 42 return b; 43 } 44 int out_max(int l,int r){ 45 int m=floor(log((double)(r-l+1))/log(2.0)); 46 int a=max(mx[l][m],mx[r-(1<<m)+1][m]); 47 return a; 48 } 49 int main() 50 { 51 int i,l,r; 52 int T,C,L,R; 53 scanf("%d",&T); 54 while(T--){ 55 scanf("%d",&n); 56 for(i=1;i<=n;i++) scanf("%d",&h[i]); 57 rmq_init(); 58 scanf("%d",&q); 59 while(q--){ 60 scanf("%d%d%d",&C,&L,&R); 61 if(C == 1) 62 printf("%d\n",out_min(L,R)); 63 else if(C == 2) 64 printf("%d\n",out_max(L,R)); 65 else if(C == 3) 66 printf("%d\n",rmq(L,R)); 67 } 68 } 69 return 0; 70 }