UVA11235 - Frequent values (QMQ问题)

Problem F: Frequent values

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.

Input Specification

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.

Output Specification

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

Sample Input
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
Sample Output
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;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值