图片加载可能有点慢,请跳过题面先看题解,谢谢
可以注意到一点,数列非降,也就是说,对于一个数而言,它存在的范围是一个区间,这样就很好写了
记这几个东西:
- \(num[i]\):\(i\) 点的数值离散化后的编号;
- \(sum[i]\):\(i\) 点的的数值出现的次数;
- \(l[i]\):\(i\) 点的数值出现的最左端;
- \(r[i]\):\(i\) 点的数值出现的最右端;
然后这不就是一个 \(RMQ\) 问题嘛。。。
对于一个询问,
如果 \(num[R]=num[L]\),则答案为:\(R-L+1\),
否则答案为:\(max(max(r[L]-L+1,R-l[R]+1),max(sum[k])),k\ \epsilon \ [num[l]+1,num[r]-1]\)
$
$
//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }
int n,q,cnt,Log[100010];
int a[100010],l[100010],r[100010];
int sum[100010],num[100010],Max[100010][20];
il void LOG(){ for(int i=1;i<=100000;i++) Log[i]=(int)(log(i)/log(2)); }
il void init(){
q=gi(),cnt=0,a[0]=200000,a[n+1]=200000;
for(int i=1;i<=n;i++){ a[i]=gi();
if(a[i]!=a[i-1]) cnt++,sum[cnt]=0;
num[i]=cnt,sum[cnt]++;
}
for(int i=1;i<=n;i++)
if(a[i]!=a[i-1]) l[i]=i;
else l[i]=l[i-1];
for(int i=n;i;i--)
if(a[i]!=a[i+1]) r[i]=i;
else r[i]=r[i+1];
}
il void pre(){
for(int i=1;i<=cnt;i++) Max[i][0]=sum[i];
for(int j=1;j<=Log[cnt];j++)
for(int i=1;i+(1<<j)<=cnt;i++)
Max[i][j]=max(Max[i][j-1],Max[i+(1<<j-1)][j-1]);
}
il int RMQ(int l,int r){
if(l>r) return 0;
int x=Log[r-l+1];
return max(Max[l][x],Max[r-(1<<x)+1][x]);
}
il void work(){
pre();
while(q--){
int L=gi(),R=gi(),ret=0;
if(num[L]==num[R]) ret=R-L+1;
else ret=max(max(r[L]-L+1,R-l[R]+1),RMQ(num[L]+1,num[R]-1));
printf("%d\n",ret);
}
}
int main(){ LOG(); while(scanf("%d",&n)&&n){ init(); work(); } return 0; }