题目大意:给你一系列按非升序排列的数字,你的任务是,给出l,r,找出这个区间[l,r]出现次数最多的值所出现的次数
解题思路:这题的话要用四个数组来记录
left[i]表示一连串和第i个数相同的数的最左边的位置
right[i]的表示最右边的数
num[i]表示第i个数所在都段的编号,段表示的是一连串数字相等的数
cnt[i]表示第i段有多少个数
记录一共共有几段,然后把每段看成一个数字,再用RMQ算法进行统计
给出的询问区间[l,r],先判断这个区间是不是包含在一个段里,如果在同一个段里,数目就是r-l+1
如果不在同一个段里,先计算左右两端共有多少个数,然后在求中间部分的最大值,左端的数目是 right[l] - l + 1,右端的数目是r - left[r] + 1,然后对这三个值取最大值即可
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100010
#define INF 0x3f3f3f3f
int left[maxn], right[maxn], cnt[maxn], num[maxn], d[maxn][20];
int n, N, Q;
void init() {
int cur = -1 ,pre = INF, x, l;
for(int i = 0; i < N; i++) {
scanf("%d", &x);
if(x == pre) {
cnt[cur]++;
num[i] = cur;
left[i] = l;
}
else {
if(cur >= 0) {
for(int j = l; j <= i - 1; j++)
right[j] = i - 1;
}
cur++;
l = i;
num[i] = cur;
left[i] = l;
cnt[cur] = 1;
pre = x;
}
}
for(int i = l; i < N; i++)
right[i] = N - 1;
n = cur + 1;
}
void RMQ_init() {
for(int i = 0; i < n; i++)
d[i][0] = cnt[i];
for(int j = 1; (1 << j) <= n; j++)
for(int i = 0; i + (1 << 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 << (1 + k)) <= 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", &Q);
init();
RMQ_init();
int l, r;
while(Q--) {
scanf("%d%d",&l,&r);
l--,r--;
if(num[l] == num[r]) {
printf("%d\n",r - l + 1);
}
else {
int t1 = r - left[r] + 1;
int t2 = right[l] - l + 1;
int t3 = RMQ(num[l] + 1,num[r]-1);
printf("%d\n",max(t1,max(t2,t3)));
}
}
}
return 0;
}