【暑假】[实用数据结构]UVa11235 Frequent values

UVa 11235 Frequent values

Time Limit: 2000MS   Memory Limit: 65536K

Total Submissions: 11241

  Accepted: 4110

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

-----------------------------------------------------------------------------------------------------------------------------------------------------------

题目:

  对于询问(L,R)输出该范围内的最多的重复次数。

思路:

一开始想到的是将每个数的出现次数加入RMQ.A 这样就可以满足题意。

但考虑到一个数可以重复出现多次时间方面不是很乐观,还有更优的方法: 将每段相同数作为一结点,该数字出现次数作为结点信息加入RMQ.A。问题就是如何将pos(L,R)转化到段上(pos是位置),为每一个pos添加信息:

  1. num[u]: 表示数字u属于的结点标号
  2. left[u]和right[u]:分别表示该数字段左端点与右端点。

那么对于询问(L,R)可以如是组织答案:

ans=max{ right[L]-L+1 , R-left[R]+1 , RMQ(num[L]+1,num[R]-1)}

  

需要注意的是一些边界的处理,如果处理不好可能会死程序。

*在长度与序号的运算中:

序号+长度-1=序号

     序号-长度+1=序号   

     序号-序号+1=长度

代码:

 1 #include<cstdio>
 2 #include<vector>
 3 #define FOR(a,b,c) for(int a=(b);a<(c);a++)
 4 using namespace std;
 5
 6 const int maxn = 100000+10;
 7 const int maxlog = 20;
 8
 9 struct RMQ{ //范围最大值
10 int d[maxn][maxlog];
11
12   //DP
13   void init(const vector<int>& A){
14       int n=A.size();
15       FOR(i,0,n) d[i][0]=A[i];
16       for(int j=1;(1<<j)<=n;j++)
17        for(int i=0;i+(1<<j)-1<n;i++)  //i+(1<<j)-1  :序号 < n
18         d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]); //1<<(j-1)
19   }
20
21   int Query(int L,int R){ //建立在L<R的基础上
22       int k=0;
23       while(1<<(k+1) <= (R-L+1)) k++;
24       return max(d[L][k],d[R-(1<<k)+1][k]);
25   }
26 };
27
28 int a[maxn],num[maxn],left[maxn],right[maxn];
29 int n,m;
30 RMQ rmq;
31
32 int main(){
33   while(scanf("%d%d",&n,&m)==2 && n){
34       FOR(i,0,n) scanf("%d",&a[i]);
35       a[n]=a[n-1]+1;  //哨兵 //保证最后一段的处理 **
36     vector<int> count;
37     //RMQ.A中每一段相同数字为一结点,数值为长度,所以RMQ 提供操作Query为 L段到R段的最大长度
38     int start=-1;
39     FOR(i,0,n+1) if(i==0 || a[i-1]<a[i]){  //新的一段
40     //处理旧的一段
41         if(i>0){   //if i==0 则只有start重载为0
42             count.push_back(i-start);    //将旧一段的长度加入RMQ.A
43             FOR(j,start,i){             //赋值 旧一段每个位置p 信息num left right
44                 num[j]=count.size()-1; left[j]=start; right[j]=i-1;
45                 //num记录结点标号
46             }
47         }
48         start = i;  //开始新的一段 start记录开始一段的头序号
49     }
50     rmq.init(count);
51     FOR(i,0,m){
52         int L,R;
53         scanf("%d%d",&L,&R); L--;R--;  //缩 序号
54         int ans=0;
55         if(num[L]==num[R]) ans=R-L+1;  //特殊情况 LR处于一段
56         else {
57             ans=max(right[L]-L+1,R-left[R]+1);
58             if(num[L]+1 < num[R]) ans=max(ans,rmq.Query(num[L]+1,num[R]-1));
59             //if num[L]+1==num[R]则RMQ 调用出错
60         }
61         printf("%d\n",ans);
62     }
63   }
64   return 0;
65 }

 

时间: 2024-08-10 21:42:59

【暑假】[实用数据结构]UVa11235 Frequent values的相关文章

uva11235(Frequent values)(HDU1806)

题目地址:Frequent values 题目大意.解题思路:  见白皮书p198. 代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int M=100100; 8 int a[M]; 9 int val[M],cn

[uva11235]Frequent values(RMQ,ST,离散化)

题目链接:https://vjudge.net/problem/UVA-11235 题意:给一串不递减数字,q次询问,每次查询[l,r]内出现次数最多的数字出现的次数. 查询分两部分:一部分是[l,r]为同一个数的区间,另一部分则是在上下界处截取一部分的情况. 首先离散化,后用l[],r[],v[]分别记录每一段相同数字的左右区间和出现次数.v可以直接由r-l+1更新得到. 第一部分更新ret后,接下来的rmq分三部分: 第一部分查询左边界截取一部分的数字的当前长度,第二部分查询右边界的,第三部

UVA-11235 Frequent values (RMQ)

题目大意:在一个长度为n的不降序列中,有m次询问,每次询问(i,j)表示在区间(i,j)中找出出现次数最多的元素的出现次数. 题目分析:因为序列有序,可以将序列分段,并且记录每段的元素个数.每一个元素所属的段num(i).每一个元素所属段的左端点l(i)及右端点r(i).那么对于每次询问: ans(i,j)=max(max(r(i)-i+1,j-l(j)+1),rmq(num(i)+1,num(j)-1)). ans(i,j)=r-j+1 (如果i与j属于同一段) 代码如下: # include

Uva11235 Frequent values (RMQ)

///对于每个询问(l,r),分为两个部分,前半部分求与l之前相同的数的个数直到t,后半部分从t开始直接用RMQ求解最大值就行了. ///最后结果为max(前半部分,后半部分). # include <algorithm> # include <string.h> # include <math.h> # include <iostream> using namespace std; int f[100100];///前i个有多少个相同的数 int dp[1

UVA11235 - Frequent values(BMQ)

题目链接 题目大意:可以一串不递减的序列,然后给你一个范围L,R,要求你返回L,R出现最多次的那个值的出现次数. 解题思路:将这个序列重新编码一下,把相同的数字标记成一段,然后用num记录是哪一段,用cnt记录一下出现了多少个相同的.然后查询的时候因为可能出现从一段中的某个部分开始的情况,所以要先将头和尾处理一下,标记每一段的最左端和最右端位置.中间完整的部分用BMQ. #include <cstdio> #include <cstring> #include <vector

[UVa11235]Frequent values

题目大意:给一个非降序排列的整数数组a,你的任务是对于一系列询问(i, j),回答ai,ai+1...aj中次数出现最多的值所出现的次数. 解题思路:由于是非降序排列,所有相同的数都是连在一起的. 本题可用RMQ做,但是我不会啊. 其实这题可以直接用线段树做(什么?RMQ可以用线段树做?我还是不会啊),不过需要保存三个东西,该区间出现最多的数出现的次数,该区间最左边的数出现的次数,该区间最右边出现的次数. 为什么要保存左边和右边的出现次数呢?例如区间$[1,10]$分为区间$[1,5]$和$[6

[POJ3368][UVA11235] Frequent values[ST表]

题意:给出一个不降序列,有多个询问,询问[l,r]中出现次数最多的数的出现次数 多组数据 对于序列-1 -1 1 1 1 1 3 10 10 10 可以这么理解<-1,2>, <1, 4>, <3,1>, <10,3> cnt[i]记录这个数字的出现次数,lef[i]记录左端点,righ[i]记录右端点,belong[i]代表第i个数字属于哪一块 把块和数量丢进st表 然后对于区间[l,r],答案就是 \(min(r, righ[l])-l+1\),\(r-

POJ 3368:Frequent values RMQ

Frequent values 题目链接: http://poj.org/problem?id=3368 题意: 给出一个非递减序列,求区间内最多的数字的数量 题解: 水题,dp[i][j]记录从 i 开始2^j个数中的出现最多的数,合并dp[i][j]和dp[i+(1<<j)][j]得到dp[i][1<<(j+1)]的时候,由于序列是连续的,只要多考虑一个i+(1<<j)-1(即dp[i][j]所能到达的最右端)上得数字在区间内出现的次数就好了. 代码 #includ

uva 11235 - Frequent values(RMQ)

题目链接:uva 11235 - Frequent values 题目大意:给定一个非降序的整数数组,要求计算对于一些询问(i,j),回答ai,ai+1,-,aj中出现最多的数出现的次数. 解题思路:因为序列为非降序的,所以相同的数字肯定是靠在一起的,所以用o(n)的方法处理处每段相同数字的区间.然后对于每次询问: num[i]=num[j]:j?i+1 numi≠numj:max(RMQ(righti+1,reftj?1),max(righti?i+1,j?leftj+1)) #include