poj3264_RMQ_ST
这个题昨天做过,但是今天使用的是RMQ_ST算法,网上关于RMQ还有中笛卡尔树的算法,今天我用的是ST算法,这个算法很给力,在初始化之后可以在O(1)的时间内求出最大值和最小值。
先简要介绍一下ST算法,ST算法需要辅助数组f[i][j]表示从第i个元素开始连续2^j个元素中的最大值(这里以最大值举例),有:
1.初始 f[i][0]=a[i]
2.对于f[i][j] j>0 有f[i][j]=max( f[i][j-1] , f[i+2^(j-1)][j-1] ),当然每次比较之前必须保证i+2^(j-1)<=n中
在初始化的过程中 j:1--m 这样保证f[1][1]=max(f[1][0],f[2][0])被比较的两个对象已经赋值,其中m=log(n)/log(2.0)
然后就可以在o(1)的时间对所给的区间(s,e)找出最大值了,这里需要将(s,e)分成两个长度为2^n的区间,这两个区间跟f[]相对应
中间值k=log(e-s+1)/log(2)
res=max(f[s][k],f[e-2^k+1][k])
以下是RMQ_ST的代码:
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 using namespace std; 5 6 const int maxnum=50005; 7 int f[maxnum][15+1]; //max数组 8 int g[maxnum][15+1]; //min数组 9 int a[maxnum]; 10 int n,q; 11 12 void RMQInit() 13 { 14 int i; 15 for(i=1;i<=n;i++) 16 { 17 f[i][0]=a[i]; 18 g[i][0]=a[i]; 19 } 20 21 int m=log((double)maxnum)/log((double)2); 22 int j; 23 for(j=1;j<=m;j++) 24 for(i=1;i<=n;i++) 25 { 26 f[i][j]=f[i][j-1]; 27 if( i+(1<<(j-1)) <= maxnum) //+的优先级比<<要高,所以得加括号 28 f[i][j]=f[i][j]>=f[i+(1<<(j-1))][j-1]?f[i][j]:f[i+(1<<(j-1))][j-1]; 29 30 g[i][j]=g[i][j-1]; 31 if(i+(1<<(j-1))<=maxnum) 32 g[i][j]=g[i][j]<=g[i+(1<<(j-1))][j-1]?g[i][j]:g[i+(1<<(j-1))][j-1]; 33 } 34 } 35 36 int RMQ_Max(int s,int e) 37 { 38 int k; 39 k=log((double)(e-s+1))/log((double)2); //+1 40 return f[s][k]>=f[e-(1<<k)+1][k]?f[s][k]:f[e-(1<<k)+1][k]; //这里左移的都是1 41 42 } 43 44 int RMQ_Min(int s,int e) 45 { 46 int k; 47 k=log((double)(e-s+1))/log((double)2); //+1 48 return g[s][k]<=g[e-(1<<k)+1][k]?g[s][k]:g[e-(1<<k)+1][k]; 49 50 } 51 52 int main() 53 { 54 scanf("%d%d",&n,&q); 55 int i; 56 for(i=1;i<=n;i++) 57 scanf("%d",&a[i]); 58 RMQInit(); 59 60 int s,e; 61 for(i=1;i<=q;i++) 62 { 63 scanf("%d%d",&s,&e); 64 printf("%d\n",RMQ_Max(s,e)-RMQ_Min(s,e)); 65 } 66 return 0; 67 }
这个题也是tju oj的2762