POJ 3368 RMQ

来源:互联网 发布:php 微信退款接口demo 编辑:程序博客网 时间:2024/06/06 12:20

http://poj.org/problem?id=3368

#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string.h>const int M=100010; // num[i] 位置i所在段    value[i],count[i] 第i段的值和出现次数 long k,n,a[M],num[M],value[M],count[M],left[M],right[M]; //第k段的左右端点 long dp[M][25];// dp[i][j] 以 i开头 长度为 2^j序列中的最大值 long Max(long a,long b){return a>b? a:b;}void RMQ(){long i,j;for(i=1;i<=k;i++) //初始化dp {dp[i][0]=count[i];}//dp[i][j]=Max(dp[i][j-1],dp[i+2^(j-1)][j-1])for(j=1;(1<<j)<=k;j++) //2^j不大于总数 n {for(i=1;i+(1<<(j-1))<=k;i++){dp[i][j]=Max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}}}long Query(long l,long r)   {long k=0;   k=log((double)(r-l+1))/log(2.0);  //     2^(k) <=r-l+1<= 2^(k+1) (中间肯定没空隙)      // 把 l ,r 分成两段// (l,2^k)  (r-2^k +1,r) 中间有交集没关系 不影响最大值 return Max(dp[l][k],dp[r-(1<<k)+1][k]);}int main(){long q,i,j,c,pre,l,r,max,p,t;while(scanf("%ld",&n)&&n){for(i=0;i<=n;i++){count[i]=0;}k=0;l=1;scanf("%ld",&q);for(i=1;i<=n;i++){scanf("%ld",&a[i]);//预处理 if(i==1){value[++k]=a[i];left[k]=i;count[k]++;num[i]=k;}else{if(pre==a[i]){num[i]=k;count[k]++;}else{right[k]=i-1;value[++k]=a[i];count[k]++;left[k]=i;num[i]=k;}}pre=a[i];}right[k]=n;RMQ();while(q--){max=-1;scanf("%ld%ld",&l,&r);  // 把 [l,r]分成三段  l-num[l],  num[l]+1~ num[r]-1 ,  num[r]~r if(l==r){printf("1\n");continue;}if(num[l]==num[r])  //同一段 {printf("%ld\n",r-l+1);continue;}if(max<(right[num[l]]-l+1)){max=right[num[l]]-l+1; // 长度: l所在段的右端点 - l +1}if(num[l]+1<=num[r]-1) //如果中间还有一段的话 {k=Query(num[l]+1,num[r]-1);if(max<k){max=k;}}if(max<(r-left[num[r]]+1)) //    r-r所在段的左端点+1 {max=r-left[num[r]]+1;}printf("%ld\n",max);}}return 0;}


0 0
原创粉丝点击