POJ3368(RMQ)

Frequent values

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

解题思路:

可以求出相同数的的个数(可以离散),但是如果所求区间切断了连续区间怎么办,分成三段,左边一段,右边一段,中间的就可以用线段树(不用更新,RMQ要简单一点)或者RMQ算最大值。

具体代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #define N 100005
 5 using namespace std;
 6 int a[N],lo[N],pos[N];
 7 int n,m,x,y;
 8 struct ii
 9 {
10     int sta,end;
11     int num;
12 }aa[N];
13 int f[N][20];
14 int main()
15 {
16     freopen("poj3246.in","r",stdin);
17     freopen("poj3246.out","w",stdout);
18     //RQM 初始化,把log2(i),先打表出来
19     //f[][]是以连续区间个数,不是n个
20     while((scanf("%d%d",&n,&m))==2)
21     {
22         int i=1,q=2,p=0;
23     lo[i]=0;
24     while(i<=n)
25     {
26         i++;
27         if(i==q)
28         {
29             q*=2;
30             p++;
31         }
32         lo[i]=p;
33     }
34     int pre=N;
35     int k=0;
36     for(int i=1;i<=n;i++)//aa记录连续区间的起点中点个数
37     {
38         scanf("%d",&a[i]);
39         if(a[i]!=pre)
40         {
41             k++;
42             aa[k].sta=i;
43             aa[k].end=i;//记录k的始末
44             pre=a[i];
45         }
46         else aa[k].end=i;
47         pos[i]=k;//记录下标所对应的k
48     }
49     for(int i=1;i<=k;i++)
50     aa[i].num=aa[i].end-aa[i].sta+1;
51     for(int i=1;i<=k;i++)
52     f[i][0]=aa[i].num;
53     for(int j=1;j<=lo[n]+1;j++)
54     for(int i=1;i<=k;i++)
55     if(i+(1<<j)-1<=k)
56     f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);//分成等量两段长度为1<<j-1
57     for(int i=1;i<=m;i++)
58     {
59         scanf("%d%d",&x,&y);
60         if(pos[x]==pos[y])cout<<y-x+1<<endl;
61         else
62         {
63             int a1=aa[pos[x]].end;
64             int b1=aa[pos[y]].sta;
65             int n1=a1-x+1;
66             int n2=0;
67             int n3=y-b1+1;
68             int k1=pos[x],k2=pos[y];
69             int p=lo[k2-k1+1-2];//都是连续区间个数
70             if(k2-k1-1==0)cout<<max(n1,n3)<<endl;
71             else
72             {
73                 n2=max(f[k1+1][p],f[k2-1-(1<<p)+1][p]);
74                 cout<<max(max(n1,n2),n3)<<endl;
75             }
76         }
77     }
78     }
79     return 0;
80 }

总结:

1.RMQ求最值的用法

2,RMQ(线段树)的应用,不完全用,先分成三部分,中间一部分用RMQ

3,RMQ:f[i][j]初始化f[i][0]=a[i];

f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]),递推,for(j:1-log2(n))for(i:1-n)[j是外层循环,i是内层,先推两个的最大值,然后再是四个,八个]

4.看清题目,是多组数据

时间: 2024-11-11 20:00:12

POJ3368(RMQ)的相关文章

POJ3368 Frequent values(RMQ线段树)

题目大概说给一个递增序列,询问区间出现最多的数. 用莫队算法比较直观,虽然应该会T..好像也可以主席树..不过题目给的序列是有序的,因而相同的数会聚在一起. 考虑把序列分成一段一段,使每段都包含极大的相同的数字 这样对于每一个区间查询: 可能这个区间左边或右边没有包含完整的一段,而其长度在段里对左或右端点进行二分查找就知道了 而除去两边不完整的,还要求出中间若干完整段的最大长度,这个就是用RMQ来快速解决了 于是这题就能这样解决了. 1 #include<cstdio> 2 #include&

[poj3368]Frequent values(rmq)

题意:给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之间连续出现次数最多的次数. 解题关键:统计次数,转化为RMQ问题,运用st表求解,注意边界. 预处理复杂度:$O(n\log n)$ 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 #include<iostream>

RMQ poj3368

题目链接 题目大意 有一个数字串长度为n,输入顺序为非递减,给出一个区间[L,R],要求算出区间中某个出现次数最多的数,答案为它出现的次数. 1. N<105 , 区间数cas<105 2. 多组测试,以0结尾 解题思路 因为数组是非递减序列,所以可以将数组分段.(也叫游程编码,Run Length Encoding RLE) 1.扫描一遍数组,求如下: - count[ i ] : 表示第 i 段中数字出现的次数总和 - num[ p ] : 表示位置P所在段的编号 - Left [ p ]

RMQ //poj3264,poj3368

http://poj.org/problem?id=3264 #include<iostream> #include<cstdio> #include<string> #include<cmath> #include<cstring> #define M 1000000 + 50 using namespace std; int a[M]; int maxs[M][100]; int mins[M][100]; int QueryMax(int

POJ3368Frequent values[RMQ 游程编码]

Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 17581   Accepted: 6346 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 cons

POJ3368---Frequent values(分组处理+RMQ)

Language: Frequent values Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14377 Accepted: 5244 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

dutacm.club 1094: 等差区间(RMQ区间最大、最小值,区间GCD)

1094: 等差区间 Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)Total Submissions:655   Accepted:54 [Submit][Status][Discuss] Description 已知一个长度为 n 的数组 a[1],a[2],-,a[n],我们进行 q 次询问,每次询问区间 a[l],a[l+1],-,a[r?1],a[r] ,数字从小到大

RMQ问题再临

RMQ问题再临 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 终于,小Hi和小Ho踏上了回国的旅程.在飞机上,望着采购来的特产——小Hi陷入了沉思:还记得在上上周他们去超市的时候,前前后后挑了那么多的东西,都幸运的没有任何其他人(售货员/其他顾客)来打搅他们的采购过程.但是如果发生了这样的事情,他们的采购又会变得如何呢? 于是小Hi便向小Ho提出了这个问题:假设整个货架上从左到右摆放了N种商品,并且依次标号为1到N,每次小Hi都给出一段区间[L, R],小Ho要做

[bzoj3489]A simple rmq problem

本题既不是rmq也不会simple(对我这种蒟蒻而言) 一开始只能想到树套树套树TAT然后看了看数据范围果断滚去膜拜题解. 然后才知道预先排序一下可以弄掉一个log.不过得写可持久化线段树套可持久化线段树.. 然后愉悦的开码了...感人的是竟然不用调...更感人的是交上去直接tle了. 然后从网上找了别人的代码(方法一样)发现同样的数据我要跑6s+..标称只要2s+.. 之后各种卡常还是慢了一倍TAT...最后自己写个max函数就和标程一样快了TAT这几天怎么总是出些奇怪的状况QAQ. 本来故事