[POJ] 3368 / [UVA] 11235 - Frequent values [ST算法]
University of Ulm Local Contest
Problem F: Frequent values
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 Specification
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 Specification
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
题解:因为序列a1,a2,a3...an是不下降的,所以相同的数字肯定连续集中在一段。维护d[i][0]为相同数字从左到右分别从1到n开始编号,例如样例中的d[i][0]从左到右为 1,2,1,2,3,4,1,1,2,3。这样就转化成了RMQ问题。因为没有中途修改a[i]的值,所以可以用Sparse-Table算法,d[i][j]表示从i开始长度为2^i的一段元素的最大值。维护数组Left[i],Right[i]分别为相同数字连续一段最左端的编号和最右端的编号,例如样例中的Left[i]分别为:1,1,3,3,3,3,7,8,8,8。所以,序列分布共有以下几种情况:
[1] ans=max(Right[i]-L+1,R-Left[j]+1)
[2] ans=R-L+1
[3] ans=max(max(Right[i]-L+1,R-Left[j]+1),RMQ(k))
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<ctype.h> 5 #include<stdlib.h> 6 #include<stdbool.h> 7 8 #define rep(i,a,b) for(i=(a);i<=(b);i++) 9 #define red(i,a,b) for(i=(a);i>=(b);i--) 10 #define clr(x,y) memset(x,y,sizeof(x)) 11 #define sqr(x) (x*x) 12 #define LL long long 13 14 int i,j,n,m,maxn,q, 15 a[100003],d[100003][50],Left[100003],Right[100003]; 16 17 void pre() 18 { 19 clr(d,0); 20 clr(Left,0); 21 clr(Right,0); 22 clr(a,0); 23 } 24 25 int max(int a,int b) 26 { 27 if(a>b) return a; 28 return b; 29 } 30 31 int RMQ_init() 32 { 33 int i,j; 34 35 for(j=1;(1<<j)<=n;j++) 36 for(i=1;i+(1<<j)-1<=n;i++) 37 d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]); 38 39 return 0; 40 41 } 42 43 int RMQ(int L,int R) 44 { 45 int k; 46 k=0; 47 48 while(1<<(k+1)<=R-L+1) k++; 49 50 maxn=max(d[L][k],d[R-(1<<k)+1][k]);; 51 52 return 0; 53 54 } 55 56 int Num_init() 57 { 58 int i; 59 60 a[0]=35113; 61 rep(i,1,n) 62 if(a[i]!=a[i-1]) Left[i]=i; 63 else Left[i]=Left[i-1]; 64 65 a[n+1]=35113; 66 red(i,n,1) 67 if(a[i]!=a[i+1]) Right[i]=i; 68 else Right[i]=Right[i+1]; 69 70 71 return 0; 72 } 73 74 int main() 75 { 76 int i,x,y; 77 78 while(true) { 79 pre(); 80 scanf("%d",&n); 81 82 if(n==0) exit(0); 83 scanf("%d",&q); 84 a[0]=35113; 85 rep(i,1,n) { 86 scanf("%d",&a[i]); 87 if(a[i]!=a[i-1]) d[i][0]=1; 88 else d[i][0]=d[i-1][0]+1; 89 90 } 91 92 Num_init(); 93 RMQ_init(); 94 95 while(q--) { 96 scanf("%d%d",&x,&y); 97 if(Left[x]==Left[y]) printf("%d\n",y-x+1); 98 else { 99 if(Right[x]+1==Left[y]) printf("%d\n",max(Right[x]-x+1,y-Left[y]+1)); 100 else { 101 RMQ(Right[x]+1,Left[y]-1); 102 printf("%d\n",max(max(Right[x]-x+1,y-Left[y]+1),maxn)); 103 } 104 } 105 } 106 } 107 108 109 return 0; 110 }