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

来源:互联网 发布:淘宝客域名注册 编辑:程序博客网 时间:2024/06/06 00:02
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 102 31 105 100

Sample Output

143

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

 

题目:

  对于询问(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 }

 

 

 

 

 

0 0