UVA11235: Frequent values(RMQ)

You are given a sequence of integers a, a, . . . , ain non-decreasing order. In addition to that, you are given several queries consisting of indices and (1 ≤ ≤ ≤ n). For each query, determine the most frequent value among the integers ai,...,aj.

Input

The input consists of several test cases. Each test case starts with a line containing two integers and(1 ≤ n, q ≤ 100000). The next line contains integers a1, . . . , a(100000 ≤ a≤ 100000, for each∈ {1,...,n}) separated by spaces. You can assume that for each ∈ {1,...,n − 1}a≤ ai+1. The following lines contain one query each, consisting of two integers and (1 ≤ ≤ ≤ n), which indicate the boundary indices for the query.

The last test case is followed by a line containing a single ‘0’.Output

For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.

Note: A naive algorithm may not run in time!Sample Input

10 3
-1 -1 1 1 1 1 3 10 10 10 23
1 10
5 10
0

Sample Output

1 4 3

/*
   这是一个有条件的区间出现次数查询, 相同的元素是放到一起的, 这简化了查询的操作.
   用 Sparse Table 可以简单实现, 这种查询.

   因为所有相同的元素是聚到一起的, 所以把相同的元素视作一个单元, 并给每一个单元编号.
   这个单元的基本特征是最左端元素的位置, 最右端元素的位置, 元素的值和元素出现的次数(元素出现的次数可以用左右端点相减表示).

   关于 Sparse Table 我的模版如下
   查询操作的时间复杂度是 loglogn
   预处理的时间复杂度是 nlogn

   st表主要注意的地方是, 查询的二分要用upper_bound, 不能用 lower_bound
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
const int MAXN = 1e5 + 600;
const int MAX_LOG2 = 20;
int st[MAXN][MAX_LOG2];
int bthPower[MAX_LOG2]; // 2th power, b == binary == 2
int _size;
void ST(int *  a, int _n){
    _size = _n;
    bthPower[0] = 1;
    for(int i = 1; i < MAX_LOG2; ++i){
        bthPower[i] = bthPower[i - 1] << 1;
    }

    for(int i = 0; i < _size; ++i){
        st[i][0] = a[i];
    }

    for(int j = 1; bthPower[j] <= _size; ++j){
        for(int i = 0; i + bthPower[j] - 1 < _size; ++i){
            st[i][j] = std::max(st[i][j - 1], st[i + bthPower[j - 1]][j - 1]);
        }
    }
}
int query(int lo, int hi){
    int length = hi - lo + 1;
    int power = std::upper_bound(bthPower, bthPower + MAX_LOG2, length) - bthPower - 1;
    return std::max(st[lo][power], st[hi - bthPower[power] + 1][power]);
}
int cnt;
int value[MAXN], Count[MAXN], Left[MAXN], Right[MAXN];
int a[MAXN];
int n, q;
int lo, hi;
int main(){
    while(scanf("%d", &n) && n){
        cnt = 0; // 当前段的数量
        scanf("%d", &q);

        for(int i = 0; i < n; ++i){
            scanf("%d", a + i);
        }

        // 先将第一个元素看作第一段, 简化处理
        value[0] = a[0];
        Count[0] = 1;
        Left[0] = 0;
        ++cnt;

        for(int i = 1; i < n; ++i){
            if(a[i - 1] != a[i]){
                Right[cnt - 1] = i - 1;
                Left[cnt] = i;
                Count[cnt] = 1;
                value[cnt++] = a[i];
            }
            else{
                ++Count[cnt - 1];
            }
        }
        // 假想的哨兵, 和最后一个元素不同
        Right[cnt - 1] = n - 1;

        ST(Count, cnt);

        while(q--){
            scanf("%d%d", &lo, &hi);
            if(hi < lo){
                std::swap(lo, hi);
            }

            // 这里可以用空间换时间, 在开一个编号数组, 记录每一个元素所在的段的编号.
            int l = std::lower_bound(value, value + cnt, a[--lo]) - value; // 得到所在段的编号
            int r = std::lower_bound(value, value + cnt, a[--hi]) - value;

            if(l == r){
                printf("%d\n", hi - lo + 1);
            }
            else if(l + 1 == r){ // 如果l, r在前后相邻的两端, 那么
                printf("%d\n", std::max(hi - Left[r] + 1, Right[l] - lo + 1));
            }
            else{
                int tmp = std::max(hi - Left[r] + 1, Right[l] - lo + 1);
                int rst = query(l + 1, r - 1);

                printf("%d\n", std::max(tmp, rst));
            }
        }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/u013482363/article/details/80207858