UVA11235:Frequent values(RMQ)

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 Specification

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 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

lrj蓝皮书上的题,但也是做了好几遍才做对...
主要是把端点处理好。
题目大意:
给一个非降序排列的整数数组a,你的任务是对于一系列询问(i, j),回答ai,ai+1...aj中次数出现最多的值所出现的次数。

分析:
由于数列是非降序的,所以所有相等的数都会聚集在一起。这样我们就可以把整个数组进行编码。如-1,1,1,2,2,2,4就可以编码成(-1,1),(1,2),(2,3),(4,1)表示(a,b)数组中的a连续出现了b次。
用num[i]表示原数组下表是i的数在编码后的第num[i]段。left[i],right[i]表示第i段的左边界和右边界,用coun[i]表示第i段有conu[i]个相同的数。
这样的话每次查询(L, R)就只要计算(right[L]-L+1),(R-left[R]+1)和RMQ(num[L]+1, num[R]-1)这三个值的最大值就可以了。
其中,RMQ是对coun数组进行取件查询的结果。
特殊的,如果L和R在同一个区间内的话,那么结果就是(R-L+1)
#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
const int M = 1e5 + 5;
int cnt[M],num[M],lef[M],righ[M],d[M][20];  //数组d右区间不必开的过大
int n,q,sec;
void RMQ_init(int* a)
{
    int n = sec+1 ;
    for(int i = 0; i < n; i++)
    {
        d[i][0] = a[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<<(k+1)) <= r-l+1)  k++;
    return max(d[l][k],d[r-(1<<k)+1][k]);  //因为包括ta自身,所以+1

}
int main()
{
    while(~scanf("%d",&n) ,n)
    {
        scanf("%d",&q);
        int temp;   //段数从0开始
        for(int i = 0; i < n; i++)
        {
            int t;
            scanf("%d",&t);
            if(i==0){temp = t;  num[i] = sec; cnt[sec]++; lef[sec] = 0; righ[sec] = -1;}  //初始化段的端点为0
            if(temp==t) {num[i] = sec;  cnt[sec]++;    righ[sec]++;}
            else{num[i]=++sec;  cnt[sec]++;    lef[sec]=righ[sec]=i;    temp=t;}
        }
        RMQ_init(cnt);
        while(q--)
        {
            int L,R;
            scanf("%d%d",&L,&R);  L--,R--;
            if(num[L] == num[R])
            {
                printf("%d\n",R-L+1);
            }
            else
            {
                int ans = 0;
                if(num[L]+1 <= num[R]-1)  //存在中间段
                    ans = RMQ(num[L]+1,num[R]-1);
                int ans1 = max(righ[num[L]]-L+1,R-lef[num[R]]+1);  //端点
                ans = max(ans,ans1);
                printf("%d\n",ans);

            }
        }
        memset(cnt,0,n+1);
    }
    return 0;
}

做了好大一会别人家的简单模板题0000ooo.

猜你喜欢

转载自www.cnblogs.com/lwsh123k/p/9460002.html