1. 程式人生 > >UVA11235:Frequent values(RMQ)

UVA11235:Frequent values(RMQ)

tdi onu 數列 查詢 name one ive 簡單 addition

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.

UVA11235:Frequent values(RMQ)