You are given a sequence of n integersa1 , a2 , ... , anin non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.
The input consists of several test cases. Each test case starts with a line containing two integers nand q (1 ≤ n, q ≤ 100000). The next line contains n integersa1 , ... , an(-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j(1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the query.
The last test case is followed by a line containing a single 0.
For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.
10 3 -1 -1 1 1 1 1 3 10 10 10 2 3 1 10 5 10 0
1 4 3
RMQ问题:Spqrse-table
DP解决初始化问题,设ans[i][j]为从i 开始步长为 2^j 的区间中的最小值,则ans[i][j] = max(ans[i][j-1], ans[i + 2^(j - 1)][j - 1]);
则查询 ans[L][R]的结果为max(ans[L][k], ans[L + 2^k][k]);k为 使得 i+ 2^k - 1<= R的最大值。
此算法的优势在于,将步长用指数表示,因为每一个步长都能找到一个k 使得 step/2 =<2^k <= step,若 2^k == step 则ans [L][k]就是答案,若 step/2 =<2^k <= step,
则max(ans[L][k], ans[rR - 2^k + 1][k])则为答案,因为是求最大值所以重叠部分不冲突。
本题还有一个要注意的问题, 本题是非递减数列,求给定区间的最大的出现次数的次数值,可以用一个数组a[i]表示第i个位置的数组值是第几次出现,如1 ,1, 1, 2 对应a数组为1,2,3,1;
但对a数组不能直接使用Sparse-table算法
考虑这种情况: 1 1 1 2 2 2 3 4 5 5 ==》a:1 2 3 1 2 3 1 1 2
中 取得类似L--R ==>1 -- 8, 则a:2 3 1 2 3 1 1 2
L--R ==> 2 3, 则a:2 3 用 算法值为3
所以需要先计算边界情况,,保证运用 算法时 L为 对应数字是第一次出现,a中的数值为出现的次数。
【代码】
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAX = 100000 + 10;
int a[MAX],ans[MAX][25];
int n,q;
void init()
{
for(int i = 0; i < n; i++)ans[i][0] = a[i];
for(int step = 1; (1 << step) <= n; ++step)
for(int i = 0; i + (1 << step) - 1 < n; i++)// i++--> i + 步长恰好为 n- 1为止
{
ans[i][step] = max(ans[i][step - 1], ans[i + (1 << (step - 1))][step - 1]);
}
}
int rmq(int s, int e)
{
int rs = 1,rs_r = 1;
for(;s < e && a[s] < a[s + 1]; s++)rs++;// x xxyzzww找出左边界y和x重复的次数
//if(s < e)s++;
for(;e > s && a[e] > a[e - 1]; e--)rs_r++;// x xxyzzww找出右边界z和w重复的次数
//cout << rs <<"==rs_r=="<<rs_r<<endl;
rs = max(rs,rs_r);
if(e - s > 1){e--; s++;}
else return rs;
int step = 0;
//测试 step 当满足条件时才 +1,在判断条件中 用+1的step作为参数,为真才 ++
while(s + (1<<(step + 1)) - 1 <= e)++step;//k为最大的 2^k < l r之间长度的值
return max(rs, max(ans[s][step],ans[e - (1 << step) + 1][step]));
}
int main()
{
while(1)
{
scanf("%d",&n);
if(!n)break;
scanf("%d",&q);
int pre,cur,count;
scanf("%d",&pre);
count = a[0] = 1;
for(int i = 1; i < n; i++)
{
scanf("%d", &cur);
if(cur == pre)count++;
else count = 1;
a[i] = count;
pre = cur;
}
init();
int s,e;
while(q--)
{
scanf("%d%d",&s,&e);
printf("%d\n", rmq(s - 1, e - 1));
}
}
return 0;
}