题意:给一个非降序的数组a1~an,对一系列询问q(l,r),找出al~ar中出现最多的数出现的次数。
思路:Sparse-Table算法。由于是非降序列,这个问题可以转化为RMQ问题,方法是把a1~an中连续相同的数合并起来,构造一个新的序列,表示每一段有几个相同的数。然后就可以把查询对应到新序列,找出相应区间的最大值。当然,首尾两段需要特殊处理。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
#define maxn 100010
int a[maxn]; //数据
int cnt[maxn]; //段长度
int L[maxn]; //段最左边
int R[maxn]; //段最右边
int num[maxn]; //下标对应段,其实后来用不到
int d[maxn][18];
int main(){
int n,q;
while(cin>>n){
if(!n)break;
cin>>q;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
a[n+1]=-100001;
int t=1; L[1]=1;
for(int i=1;i<=n;i++){
num[i]=t;
if(a[i+1]!=a[i]){
R[t]=i;
d[t][0]=cnt[t]=R[t]-L[t]+1;
if(i!=n){
t++;
L[t]=i+1;
}
}
}
for(int j=1;(1<<j)<=t;j++){
int x=1<<(j-1);
for(int i=1;i<=t;i++){
d[i][j]=max(d[i][j-1],d[i+x][j-1]);
}
}
for(int i=1;i<=q;i++){
int l,r;
scanf("%d%d",&l,&r);
if(num[l]==num[r]){
printf("%d\n",r-l+1);
}else if(num[l]+1==num[r]){
printf("%d\n",max( R[num[l]]-l,r-L[num[r]] )+1 );
}else{
int range=num[r]-num[l]-1;
int x=0;
while((1<<x)<=range)x++;
x--;
int tmp=max( R[num[l]]-l,r-L[num[r]] )+1;
printf("%d\n",max( tmp, max(d[num[l]+1][x],d[num[r]-(1<<x)][x] ) ) );
}
}
}
return 0;
}