POJ3368 Frequent Values [RMQ] [线段树]

12 篇文章 0 订阅
1 篇文章 0 订阅

Frequent values
Time Limit: 2000MS
Memory Limit: 65536KB
64bit IO Format: %lld & %llu

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
Ulm Local 2007


一句话,多次查询区间的众数的次数

注意多组数据!!!!

RMQ方法:

预处理 i 及其之前相同的数的个数

再倒着预处理出 i 到不是与 a[i] 相等的位置之前的一个位置, 查询时分成相同的一段和不同的一段 (RMQ)

但是要注意 to[i] 大于查询范围的情况, 以及RMQ时 x < y 的情况!!

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100005;
const int maxd=20;
int n,q;
int a[maxn];
int sum[maxn];
int to[maxn];
inline bool init()
{
    if(!~scanf("%d%d",&n,&q) || !n) return false;
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    sum[1]=1;
    for(int i=2;i<=n;i++)
        if(a[i-1]^a[i]) sum[i]=1;
        else sum[i]=sum[i-1]+1;
    to[n]=n;
    for(int i=n-1;i;i--)
        to[i] = a[i]^a[i+1]? i : to[i+1];
    return true;
}
int dp[maxn][maxd];
void ST()
{
    for(int i=1;i<=n;i++) dp[i][0] = sum[i];
    int k=0;
    while( (1<<k+1) <= n ) k++;
    for(int j=1;j<=k;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dp[i][j] = max( dp[i][j-1] , dp[i+(1<<j-1)][j-1] ); // j-1 moved !!!
}
inline int RMQ(int x,int y)
{
    if (x>y) return -INF; // INF here to make the case extinct!!
    int k=0;
    while( (1<<k+1) <= (y-x+1) ) k++;
    return max(dp[x][k] , dp[y-(1<<k)+1][k]);
}
int main()
{
    freopen("fre.in","r",stdin);
    freopen("fre.out","w",stdout);
    while(init())
    {
        ST();
        for(int i=1;i<=q;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",max(sum[min(to[x],y)]-sum[x]+1 , RMQ(to[x]+1,y)));
        }
    }
    return 0;
}

线段树写法。。。。还没写,给个链接
http://blog.csdn.net/lanjiangzhou/article/details/8993285

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值