uva 11235 Frequent values

本文从WordPress迁移而来, 查看全部WordPress迁移文章

线段树

题意:给出一段不下降序列,只有询问没有修改,每次询问一段区间内,连续的数字最大个数是多少(是个数,好像1 1 1 1,重复了4次,次数又最大,那么输出4)

比较简单的线段树,用分治的思想去解决

一个线段树需要记录的信息有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct SegTree{
int l,r; //左右区间端点
int pre,presum; //前缀数字,以及这个数字重复了几次,即一个前缀和
int suf,sufsum; //后缀数字,以及这个数字重复了几次,即一个后缀和
int Max; //该区间最大重复次数
SegTree(){}
SegTree(int _l,int _r){
l = _l; r = _r;
presum = sufsum = Max = -INF;
}
int mid(){
return (l + r) >> 1;
}
int callen(){
return r - l + 1;
}
}t[N<<2];

建树时,通过一个自底向上的更新,将左右孩子的信息汇聚到当前区间里,为了函数可以重用,代码不写PushUp,改写为Del,因为这个函数在查询时还需要用到。

自底向上的更新是

  1. 当前区间的前缀和后缀,分别是左孩子的前缀和右孩子的后缀
  2. 当前区间的前缀和等于左孩子的前缀和,如果左孩子的前缀和等于左孩子区间长度(即整个区间都是这个数字),并且右孩子的前缀和左孩子的前缀相同,那么当前区间的前缀还可以延伸到右孩子区间去;rt.presum = lson.presum + rson.presum
  3. 同理,对于后缀和也是这样的,要么等于右孩子的后缀和,如果右孩子的后缀能延伸到左孩子的后缀,那么rt.sufsum = rson.sufsum + lson.sufsum
  4. 当前区间的最大重复次数,要么等于左孩子的最大重复次数,要么等于右孩子的最大重复次数,要么左孩子的后缀 = 右孩子前缀,可以将左孩子后缀和 + 右孩子前缀和

对于查询操作,和build tree的道理是一样的,都是分治

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 100010
#define INF 0x3f3f3f3f
#define lson(i) ((i)<<1)
#define rson(i) ((i)<<1|1)

int n;
struct SegTree{
int l,r;
int pre,presum;
int suf,sufsum;
int Max;
SegTree(){}
SegTree(int _l,int _r){
l = _l; r = _r;
presum = sufsum = Max = -INF;
}
int mid(){
return (l + r) >> 1;
}
int callen(){
return r - l + 1;
}
}t[N<<2];

void Del(SegTree &a,SegTree &b,SegTree &res){
res.pre = a.pre; res.suf = b.suf;
if(a.presum == a.callen() && a.pre == b.pre)
res.presum = a.presum + b.presum;
else
res.presum = a.presum;
if(b.sufsum == b.callen() && b.suf == a.suf)
res.sufsum = b.sufsum + a.sufsum;
else
res.sufsum = b.sufsum;
res.Max = max(a.Max,b.Max);
if(a.suf == b.pre)
res.Max = max(res.Max,a.sufsum+b.presum);
}

void build(int rt,int a,int b){
t[rt] = SegTree(a,b);
if(a == b){
int x;
scanf("%d",&x);
t[rt].pre = t[rt].suf = x;
t[rt].presum = t[rt].sufsum = t[rt].Max = 1;
return ;
}
int mid = t[rt].mid();
build(lson(rt),a,mid);
build(rson(rt),mid+1,b);
Del(t[lson(rt)],t[rson(rt)],t[rt]);
}

SegTree query(int rt,int a,int b){
if(t[rt].l == a && t[rt].r == b){
return t[rt];
}
int mid = t[rt].mid();
if(b <= mid)
return query(lson(rt),a,b);
else if(a > mid)
return query(rson(rt),a,b);
else{
SegTree res;
SegTree res1 = query(lson(rt),a,mid);
SegTree res2 = query(rson(rt),mid+1,b);
res.l = res1.l; res.r = res2.r;
Del(res1,res2,res);
return res;
}
}

int main(){
int q;
while(scanf("%d",&n)!=EOF && n){
scanf("%d",&q);
build(1,1,n);
while(q--){
int x,y;
scanf("%d%d",&x,&y);
SegTree res = query(1,x,y);
printf("%d\n",res.Max);
}
}
return 0;
}