码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-07 19:01:57      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:

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 }

 

 

 

 

 

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

标签:

原文地址:http://www.cnblogs.com/lidaxin/p/4711527.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!