Frequent values(线段树+离散化)

http://poj.org/problem?id=3368

题意:给出一个非降序排列的整数数组,对于询问(i,j),输出区间[i,j]中出现最多的值的次数。

思路:经典的RMQ,不过我用线段树做的。首先要离散化,因为是非降序的,所以相同的数是连续的,可以将相同的数分在同一个块中,将块中的信息存储起来,然后将其看成一个点,就可以用线段树进行查询了。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N=1000010;
 6 struct node
 7 {
 8     int l,r;
 9     int Max;
10 } Tree[N*4];
11 struct point//记录每块的信息
12 {
13     int s,t;//s起始位置,t结束位置
14     int cnt;//块中的数出现的次数
15 } block[N];
16 int v[N],num[N];//num[i]表示第i个数被分在第几块
17 void build(int l,int r,int rt)
18 {
19     Tree[rt].l = l;
20     Tree[rt].r = r;
21     if (l==r)
22     {
23         Tree[rt].Max = block[l].cnt;
24         return ;
25     }
26     int mid = (l+r)>>1;
27     build(l,mid,rt<<1);
28     build(mid+1,r,rt<<1|1);
29     Tree[rt].Max=max(Tree[rt<<1].Max,Tree[rt<<1|1].Max);
30 }
31 int Query(int l,int r,int rt)
32 {
33     if(Tree[rt].l==l&&Tree[rt].r==r)
34         return Tree[rt].Max;
35     int mid=(Tree[rt].l+Tree[rt].r)>>1;
36     if (r <= mid)
37         return Query(l,r,rt<<1);
38     else if (l > mid)
39         return Query(l,r,rt<<1|1);
40     else
41         return max(Query(l,mid,rt<<1),Query(mid+1,r,rt<<1|1));
42 }
43 int main()
44 {
45     int n,q;
46     while(~scanf("%d%d",&n,&q)&&n)
47     {
48         memset(block,0,sizeof(block));
49         for (int i = 1; i <= n; i++)
50             scanf("%d",&v[i]);
51         int m=1;
52         block[m].s=1;
53         for (int i = 1; i <= n; i++)//将相同的数分在同一块
54         {
55             num[i]=m;
56             if(v[i]!=v[i+1]||i==n)
57             {
58                 block[m].t = i;
59                 block[m].cnt=block[m].t-block[m].s+1;
60                 block[++m].s = i+1;
61             }
62         }
63         build(1,m-1,1);//将每一块看成一个点,建树
64         while(q--)
65         {
66             int l,r;
67             scanf("%d%d",&l,&r);
68             if (num[l]==num[r])//在同一个块里,则[l,r]是连续的相同的数
69                 printf("%d
",r-l+1);
70             else               //不在同一个块里
71             {
72                 int cnt1 = block[num[l]].t-l+1;//l所在块中,区间[l,block[num[l]].t]中相同的数的次数
73                 int cnt3 = r-block[num[r]].s+1;//r所在块中,区间[block[num[r]].s,r]中相同的数的次数
74                 int cnt2 = 0; 
75                 if (num[r]-num[l]>1)//大于两个块
76                     cnt2 = Query(num[l]+1,num[r]-1,1);//中间块相同数出现的最多次数
77                 int ans = max(max(cnt1,cnt3),cnt2);
78                 printf("%d
",ans);
79             }
80         }
81     }
82     return 0;
83 }
View Code
原文地址:https://www.cnblogs.com/lahblogs/p/3557967.html