傳送門:UVa 11235
題目描述:給一個非降序排列的整數數組,對於一系列詢問[L,R],回答在此區間中出現次數最多的值出現的次數。
數組是非降序排列,因此相同的元素會排在一起,用value[]和cont[]記錄不同的元素及出現的次數,然後用num[],Left[]和Right[]數組維護第i位的元素出現在哪一段內以及這個元素在最左邊的位置和最右邊的位置。利用RMQ維護cont,記錄最大值。
當進行查詢時,首先判斷L和R是否在同一段內,如果是,則答案爲R-L+1;否則需要選擇Right[L]-L+1,RMQ(num[L]+1,num[R]-1)和R-Left[R]+1三段的最大值。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=100050;
int c[maxn];
int value[maxn],cont[maxn];
int Left[maxn],Right[maxn],num[maxn];
int d[maxn][1005];
int RMQ_init(int n)
{
for(int i=1;i<=n;i++) d[i][0]=cont[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+j-1<=n;i++)
d[i][j]=max(d[i][j-1],d[i+(1<<j-1)][j-1]);
}
int RMQ(int L,int R)
{
if(L>R) return 0;
int k=0;
while((1<<k+1)<=R-L+1) k++;
return max(d[L][k],d[R-(1<<k)+1][k]);
}
int main()
{
int n,Q;
while(cin>>n)
{
if(n==0) break;
cin>>Q;
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
memset(Left,0,sizeof Left);
memset(Right,0,sizeof Right);
int t=0,tmp=c[1];
value[++t]=c[1];cont[t]=1;
num[1]=1;Left[1]=1;
for(int i=2;i<=n;i++)
{
if(tmp==c[i])
{
cont[t]++;
num[i]=t;
Left[i]=Left[i-1];
}
else
{
Right[i-1]=i-1;
tmp=c[i];value[++t]=c[i];
cont[t]=1;
num[i]=t;
Left[i]=i;
}
}
Right[n]=n;
for(int i=n-1;i>=1;i--)
{
if(Right[i]==0)
{
Right[i]=Right[i+1];
}
}
RMQ_init(t);
while(Q--)
{
int L,R;
scanf("%d %d",&L,&R);
if(num[L]==num[R]) printf("%d\n",R-L+1);
else
{
int tmp1=Right[L]-L+1;
int tmp2=RMQ(num[L]+1,num[R]-1);
int tmp3=R-Left[R]+1;
printf("%d\n",max(max(tmp1,tmp2),tmp3));
}
}
}
return 0;
}