对上升序列如:1 1 2 2 2 3 3 4 5 5 ....... 统计区间出现次数最多数个数。
我们可以构造一个b[]数组,
if(a[i]==a[i-1])b[i]=b[i-1]+1;
else b[i]=1;
这样对上述例子,b[]数组有1 2 1 2 3 1 2 1 1 2
那么对询问区间[l,r],如果l在数与数交界处,那么直接查询l,r区间最大值。
否则要知道与a[l]相同延伸到end,那么这个区间大小end-l+1,与rmq(end+1,r)取最大值就是答案。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
const int maxn=2e5;
/*
数组下标从1到n,询问[l,r]最小值
*/
int a[maxn];
int b[maxn],c[maxn];
int dp2[maxn][32];
void ini(int n){
for(int i=1;i<=n;i++)dp2[i][0]=b[i];
for(int j=1;j<30;j++){
for(int i=n;i>=1;i--){
if(i+(1<<j-1)<=n)
dp2[i][j]=max(dp2[i][j-1],dp2[i+(1<<j-1)][j-1]);
}
}
}
inline int rmq2(int l,int r){
int k=0;
while(1<<k+1<=r-l+1)k++;
return max(dp2[l][k],dp2[r-(1<<k)+1][k]);
}
int sol(int l,int r){
if(l>r)return 0;
return rmq2(l,r);
}
int main()
{
int n,m;
while(~scanf("%d",&n)){
if(!n)break;
scanf("%d",&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(i==1||a[i]!=a[i-1])b[i]=1;
else b[i]=b[i-1]+1;
}
int p=n;
for(int i=n;i>=1;i--){
if(i==n||b[i]==b[i+1]-1)c[i]=p;
else c[i]=i,p=i;
}
ini(n);
for(int i=0;i<m;i++){
int l,r;
scanf("%d%d",&l,&r);
if(l>r)swap(l,r);
int ans0=min(c[l],r)-l+1;
int ans1=sol(min(c[l],r)+1,r);
printf("%d\n",max(ans0,ans1));
}
}
return 0;
}