POJ 3368.Frequent values-处理数据+RMQ(ST)

昨天写的博客删了,占坑失败,还是先把RMQ玩的6一点再去搞后面的东西。废话少说,题解题姐姐_(:з」∠)_ 
 
 
Frequent values
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 20960   Accepted: 7403

Description

You are given a sequence of n integers a1 , a2 , ... , an in 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

The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains n integers a1 , ... , 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

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

Source

 
 
这个题就是找数列区间中出现次数最多的数出现的次数,将数据处理一下,记录一下出现的次数,然后用RMQ区间查询最大值就可以得出结果。
这个处理很重要,首先是记录出现的次数,然后区间查询的时候,有可能将本来出现次数最多的拆开成不是最多的了,所以要处理一下。
举个例子。查询的区间为5---10,就是1 1 3 10 10 10,数据处理之后为3 4 1 1 2 3(因为前面的1是连续的,就会影响结果),这样找出来的最大值是4,但是正确的结果应该是3。
所以在RMQ之前,先判断要查询的左区间是否为前面连续的一部分,如果是的话,将区间右移,直到找到第一个第一次出现的数开始,这里就是找到处理数据之前数字3的位置,从3开始到10进行RMQ,然后将查询出来的最大值和一开始跳过去的连续的数的个数进行比较,这里就是将查询出来的结果3和一开始1出现的次数2进行比较,发现是3大,所以结果就是3。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1e5+10;
int f[maxn],num[maxn],mm[maxn][20];
int n;
void ST(){
    for(int i=1;i<=n;i++)
        mm[i][0]=num[i];
    int k=floor(log((double)n+1)/log(2.0));//最多能走2的多少次方
    for(int j=1;j<=k;j++){
        for(int i=1;i+(1<<j)-1<=n;i++)
            mm[i][j]=max(mm[i][j-1],mm[i+(1<<(j-1))][j-1]);
    }
}
int RMQ(int l,int r){
    if(l>r)return 0;
    int k=floor(log((double)(r-l+1))/log(2.0));
    return max(mm[l][k],mm[r-(1<<k)+1][k]);
}
int main(){
    int q,a,b;
    while(~scanf("%d",&n)&&n){
        scanf("%d",&q);
        for(int i=1;i<=n;i++){
            scanf("%d",&f[i]);
            if(i==1){
                num[i]=1;continue;
            }
            if(f[i]==f[i-1])
                num[i]=num[i-1]+1;
            else
                num[i]=1;
        }
        ST();
        while(q--){
            scanf("%d%d",&a,&b);
            int t=a;
            while(t<=b&&f[t]==f[t-1])t++;//处理一下连续的数对查询的影响,找到第一次出现的数的位置
            int cnt=RMQ(t,b);
            int ans=max(t-a,cnt);//将查询出来的最大值和开头跳过去的数的次数比较一下
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

总之,RMQ好像很厉害的样子,好多东西变形一下就可以用RMQ写,溜了,在写HDU的3183,写好之后写题解。

好菜啊,难受。

 

 

posted @ 2018-02-24 16:11  ZERO-  阅读(288)  评论(0编辑  收藏  举报