0%

HDU1754题:单点更新线段树

题目

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1754

I Hate It

Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 112661 Accepted Submission(s): 42042

Problem Description

很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。

不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

Input

本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。
当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。

Output

对于每一次询问操作,在一行里面输出最高成绩。

Sample Input

1
2
3
4
5
6
7
8
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5

Sample Output

1
2
3
4
5
5
6
5
9
HintHuge input,the C function scanf() will work better than cin

题解

线段树单点更新的裸题

标准的单点更新的答案:

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
#include <iostream>
using namespace std;
const int maxn=(int)1e6+10;

int a[maxn];

struct Node{
int l;
int r;
int date;
}tree[maxn*4];

void build(int x,int l,int r){
tree[x].l=l;
tree[x].r=r;
if(l==r){
tree[x].date=a[l];
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build((x<<1)|1,mid+1,r);
tree[x].date=max(tree[x<<1].date,tree[(x<<1)|1].date);

}

void update(int x,int q,int val){
if(tree[x].l==q&&tree[x].r==q){
tree[x].date=val;
return ;
}
int mid=(tree[x].l+tree[x].r)>>1;
if(q<=mid)
update(x<<1,q,val);
if(q>mid)
update((x<<1)|1,q,val);
tree[x].date=max(tree[x<<1].date,tree[(x<<1)|1].date);
}

int query(int x,int l,int r) {
if (tree[x].l >= l && tree[x].r <= r)
return tree[x].date;
int mid = (tree[x].l + tree[x].r) >> 1;
if (r <= mid)
return query(x << 1, l, r);
else if (l > mid)
return query((x << 1) | 1, l, r);
else
return max(query(x << 1, l, mid), query((x << 1) | 1, mid + 1, r));
}

int main(){
ios::sync_with_stdio(false);
int n,m,x,y;
string op;
while(cin>>n>>m){
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(m--){
cin>>op>>x>>y;
if(op[0]=='U')
update(1,x,y);
else
cout << query(1,x,y) << endl;
}
}
return 0;
}

当然这道题也可以用区间更新做,无非将区间退化为单点,也就是将[L,R]操作变成[L,L]而已

不过不建议这样做,单点更新还是老老实实套上面的板子更舒服,不过我还是先放上来吧

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
92
93
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=200010;

int a[maxn];

struct node{
int l,r;
int max,lazy;
void update(int x){
if(x>max)
max=x;
lazy=x;
}
void force(int x){
max=x;
}
}tree[maxn*4];

void push_up(int x){
tree[x].max=max(tree[x<<1].max,tree[x<<1|1].max);
}

void push_down(int x){
int val=tree[x].lazy;
if(val){
tree[x<<1].update(val);
tree[x<<1|1].update(val);
tree[x].lazy=0;
}
}

void build(int x,int l,int r){
tree[x].l=l,tree[x].r=r;
tree[x].lazy=0;
if(l==r)
tree[x].max=a[l];
else{
int mid=(l+r)/2;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
push_up(x);
}
}

void update(int x,int l,int r,int val){
int L=tree[x].l,R=tree[x].r;
if(l<=L&&R<=r)
tree[x].force(val);
else{
push_down(x);
int mid=(L+R)/2;
if(l<=mid) update(x<<1,l,r,val);
if(r>mid) update(x<<1|1,l,r,val);
push_up(x);
}
}

int query(int x,int l,int r){
int L=tree[x].l,R=tree[x].r;
if(l<=L&&R<=r)
return tree[x].max;
else{
int ans=0;
push_down(x);
int mid=(L+R)/2;
if(l<=mid) ans=max(ans,query(x<<1,l,r));
if(r>mid) ans=max(ans,query(x<<1|1,l,r));
push_up(x);
return ans;
}
}

int main(){
ios::sync_with_stdio(false);
int n,m;
while(cin>>n>>m){
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
char c;
int l,r;
while(m--){
cin>>c>>l>>r;
if(c=='Q')
cout << query(1,l,r) << endl;
else
update(1,l,l,r);
}
}
return 0;
}