poj3368--Frequent values--不递减数列的区间众数--RMQ问题

Description

给一个不递减的长度为n的数列,q个询问,每次询问[l,r]区间内众数出现的次数。

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问题来解决,还是用st算法。

  st[i][0]要记录出现次数,额外需要加一个关于断点前后各自的众数的大小的判断。因为数列不递减,(使断点和断点后一个数不相等,即在当前情况下尽可能使断点靠后)所以如果断点后出现的次数,比断点前的多,那么更新ans(取两者max)

  

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdio>
 5 using namespace std;
 6 const int maxn=100009;
 7 int a[maxn],st[maxn][20],n,q;
 8 int sum[maxn],l,r;
 9 void init_st()
10 {
11     for(int i=n;i>=1;i--)
12     {
13         st[i][0]=sum[i];
14         for(int j=1;(i+(1<<j)-1)<=n;j++)
15         {
16             st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
17         }
18     }
19 }
20 int ask(int l,int r)
21 {
22     if(l>r)return 0;
23     int k=((int)(log(r-l+1.0)/log(2.0)));
24     return max(st[l][k],st[r-(1<<k)+1][k]);
25 }
26 int main()
27 {
28     while(scanf("%d",&n)!=EOF)
29     {
30         if(n==0)break;
31         scanf("%d",&q);
32         for(int i=1;i<=n;i++)
33         {
34             scanf("%d",&a[i]);
35             if(i==1)
36             {
37                 sum[i]=1;
38                 continue;
39             }
40             if(a[i]==a[i-1])
41                 sum[i]=sum[i-1]+1;
42             else
43                 sum[i]=1;
44         }
45         init_st();
46         while(q--)
47         {
48             scanf("%d%d",&l,&r);
49             int tmp=l;
50             while(a[tmp]==a[tmp-1]&&tmp<=r) tmp++;
51             int cnt=ask(tmp,r);
52             int ans=max(cnt,tmp-l);
53             printf("%d
",ans);
54         }
55     }
56     return 0;
57 }
View Code
原文地址:https://www.cnblogs.com/Beckinsale/p/7465697.html