大体题意:
给你n 个元素的非降序排列的数组,给你m 个询问i,j,求出 区间[i,j]内出现次数最多数的次数!
思路:
RMQ算法是求某个区间内的最小值或最大值!
这个问题关键是转换到RMQ问题上去!
因为数组呈非降序,所以所有相等的元素会聚在一起!
所以可以把数组分成一块一块的, val[i]表示第i块 数值是多少,cot[i]表示第i块出现了多少次!
num[p]表示数组位置p 属于哪一块,left[p],right[p]分别表示位置p所在块的 左边位置和右边位置!
那么只需统计 num[l] + 1 到 num[r] - 1 这些块中cot最大值是多少,在哪这个答案和边界进行比较!
边界时第L段 他有right[l]-l+1个 和R所在的段 有 r-left[r]+1个!
注意右边一定要大于左边的问题!
注意有个特殊情况,如果L和R在同一段,答案是R-L+1
详细见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
int num[maxn],left[maxn],right[maxn],val[maxn],cot[maxn],a[maxn];
int n,m;
int cur;
int d[maxn][30];
void RMQ_init(){
for (int i = 0; i < cur; ++i)d[i][0] = cot[i];
for (int j = 1; (1<<j) <= cur; ++j)
for (int i = 0; i+(1<<j)-1 < cur; ++i)
d[i][j] = max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int RMQ(int l,int r){
int k = 0;
while((1<<(k+1)) <= r-l+1)++k;
return max(d[l][k],d[r-(1<<k)+1][k]);
}
int main(){
while(scanf("%d",&n) == 1 && n){
scanf("%d",&m);
memset(cot,0,sizeof cot);
cur = 0;
int last = inf;
for (int i = 0; i < n; ++i) scanf("%d",&a[i]);
for (int i = 0; i < n; ++i){
left[i] = i;
int j;
for (j = i; j < n && a[j] == a[i]; ++j){
val[cur] = a[i];
cot[cur]++;
num[j] = cur;
left[j] = i;
}
int k = j-1;
right[k] = k;
for (; k >= i; --k){
right[k] = j-1;
}
++cur;
i = j-1;
}
RMQ_init();
for (int i = 0; i < m; ++i){
int l,r;
scanf("%d %d",&l,&r);
l--;r--;
if (num[l] == num[r]){
printf("%d\n",r-l+1);
continue;
}
int t1 = num[l]+1;
int t2 = num[r]-1;
// printf("t1 = %d,t2 = %d\n",t1,t2);
int t_ans;
if (t2 >= t1)
t_ans = RMQ(t1,t2);
else t_ans = 0;
// printf("%d\n",right[l]);
int ans = max(max(t_ans,right[l]-l+1),r-left[r]+1);
printf("%d\n",ans);
}
}
return 0;
}
/*
10 3
-1 -1 1 1 1 1 3 10 10 10
*/