RMQ问题求静态区间的最值问题:
http://blog.chinaunix.net/uid-20760412-id-1872571.html
http://blog.csdn.net/detective_xin/article/details/7211135
这题的想法也很好,一开始直接是不能用RMQ的,这里用到了游程编码,将相同的连续数字压缩成一段,记录这段的数据个数,然后用RMQ算段的最值。
当然还有一些转化问题:
value[],Count[]用来记录每段的值和个数
L[],R[],num[]用来记录每段的最左端和最右端,以及记录某个点属于哪个段。
对与每对l,r,如果l和r在一段中,就为r-l+1,否则就等于R[num[l]]-l+1,r-L[num[r]]+1,RMQ(num[l]+1,num[r]-1)的最大值。
代码:
#include<iostream> #include<cstdio> #include<vector> #include<string> #include<queue> #include<cmath> #include<algorithm> #include<cstring> #define maxn 1000005 #define maxm 1000005 #define INF 0xfffffff #define mem(a,b) memset(a,b,sizeof(a)) #define FOR(i,s,t) for(int i=s;i<=t;i++) #define ull unsigned long long #define ll long long using namespace std; int value[maxn],Count[maxn]; int L[maxn],R[maxn],num[maxm];//某一段的最左端的编号,最右端的编号,某个下标所在的段 int dp[maxn][33]; void init() { memset(Count,0,sizeof(Count)); memset(dp,0,sizeof(dp)); } int n,q; void init_RMQ(int k) { for(int i=1;i<=k;i++) dp[i][0]=Count[i]; for(int j=1;(1<<j)<=k;j++) { for(int i=1;i+(1<<j)-1<=k;i++) { dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int RMQ(int l,int r) { if(r<l) return 0; int k=0; while((1<<k+1)<=r-l+1) k++;//注意这里求[l,r]中最大的k满足2^k<=r-l+1 return max(dp[l][k],dp[r-(1<<k)+1][k]); } int main() { while(scanf("%d",&n)==1) { if(!n) break; init(); scanf("%d",&q); int k=1,a; for(int i=1;i<=n;i++) { scanf("%d",&a); if(i==1) { Count[k]++; value[k]=a; num[i]=k; L[k]=i; continue; } if(value[k]!=a) { R[k]=i-1; k++; L[k]=i; value[k]=a; Count[k]++; num[i]=k; } else { Count[k]++; num[i]=k; } } R[k]=n; init_RMQ(k); for(int i=0;i<q;i++) { int l,r; scanf("%d%d",&l,&r); if(num[l]==num[r]) { printf("%d\n",r-l+1); } else { int ans1=max(R[num[l]]-l+1,r-L[num[r]]+1); int ans2=RMQ(num[l]+1,num[r]-1); printf("%d\n",max(ans1,ans2)); } } } return 0; }