poj 3368 Frequent values(离散化+RMQ)

本文介绍了一种使用离散化和RMQ(线段树)算法解决区间内最频繁值查询的问题。通过将原始数组进行离散化,将重复的值映射到唯一的下标,利用RMQ快速找到特定区间内出现次数最多的值。这种方法在处理大量重复元素的查询时,能显著提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Frequent values
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 11820 Accepted: 4320

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

题意:给出n个数,非降序排列,有q个询问,对于每个询问a,b,求出区间[a,b]中的出现次数最多的数的出现次数。

思路:先将数据离散化,用x[i]表示原数组,A[i]表示离散化后下标为i的数在原序列的出现次数,s[i]表示离散化后下标为i的数在原数组中第一次出现的位置,in[i]表示i离散化后的下标,然后rmq[i][k]存的是从i开始长度为1<<k的区间的最大A[i]值。对于每个询问(a,b),有三种情况:
(1)若x[a]==x[b],那么这个区间只有一个元素,答案为b-a+1。
(2)若in[x[a]]+1==in[x[b]],即这个区间只有两种元素,答案为两种元素在这个区间出现次数的最大值
(3)若区间的元素种数>2,则先求出首尾两种元素出现次数的最大值,因为中间的元素一定全部落在区间[a,b]上,所以可用RMQ求出中间元素出现次数的最大值。

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdlib>
#define L(rt) (rt<<1)
#define R(rt) (rt<<1|1)
#define ll long long
#define eps 1e-6
using namespace std;

const int maxn=100005;
int A[maxn+20],s[maxn+20],x[maxn+20],in[maxn*2+20],rmq[maxn+20][30];
//x[i]表示原数组
//A[i]表示离散化后下标为i的数的出现次数
//s[i]表示离散化后下标为i的数在原数组中第一次出现的位置
//in[i]表示i离散化后的下标
//rmq存最大的出现次数
int n,m,num;
void initRMQ()
{
    for(int i=1;i<=n;i++) rmq[i][0]=A[i];
    for(int k=1;(1<<k)<=n;k++)
    for(int i=1;i+(1<<k)-1<=n;i++)
    rmq[i][k]=max(rmq[i][k-1],rmq[i+(1<<(k-1))][k-1]);
}
int RMQ(int a,int b)
{
    int ia=in[x[a]],ib=in[x[b]];  //ia,ib分别是x[a],x[b]离散化后的下标
    if(ia==ib) return b-a+1;      //即x[a]==x[b]
    int sb=s[ib]; //sb分别为x[b]在x数组第一次出现的下标
    if(ia+1==ib) return max(sb-1-a+1,b-sb+1); //若[a,b]内只有两种元素
    int ans=max(s[ia+1]-1-a+1,b-sb+1);  //ans为首尾的最大值
    ia++;
    ib--;
    int k=(int)(log(ib-ia+1.0)/log(2.0));
    ans=max(ans,max(rmq[ia][k],rmq[ib-(1<<k)+1][k]));
    return ans;
}
int main()
{
    int a,b;
    while(scanf("%d",&num),num)
    {
        scanf("%d",&m);
        n=0;x[0]=0;
        memset(A,0,sizeof(A));
        for(int i=1;i<=num;i++)
        {
            scanf("%d",&x[i]);
            x[i]+=maxn;
            if(x[i]!=x[i-1])
            {
                in[x[i]]=++n;
                s[n]=i;
            }
            A[n]++;
        }
        initRMQ();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            printf("%d\n",RMQ(a,b));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值