我的博客

codevs 1080 线段树练习

目录
  1. 题解

题目描述 Description

一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数m<10000条。

输入描述 Input Description

输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。

输出描述 Output Description

共m行,每个整数

样例输入 Sample Input

6
4
5
6
2
1
3
4
1 3 5
2 1 4
1 1 9
2 2 6

样例输出 Sample Output

22
22

数据范围及提示 Data Size & Hint

1≤N≤100000, m≤10000 。

题解

单点更新,区间查询的线段树。

数组 t 是树的空间。首先我们先根据 题目给定的 n 的大小计算具体需要多少空间。r_max 是树叶子节点的个数,叶子节点一定是 2 的幂,而且大于等于 n。比如,n 为 6 的时候, r_max 是 8,这意味着树要占用 r_max * 2 - 1个数组空间,也就是 15 个空间,从下标 1 到下标 15。

其中下标 8 到 13 就存储题目给的 6 个数字。(剩下的 14、15要设为 0)下标 1 存的是第 1 到 8 个数的和,下标 2 存的是第 1 到 4 个数的和,下标 3 存第 5 到 8 个数的和,下标 4 存第一、第二个数的和,下标 5 存第二、三个数,以此类推。

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
#include <iostream>
using namespace std;

const int maxn = 131072 + 10;
long long t[maxn<<2];
int x = 0, n;

void build(int f, int l, int r) {
if (l == r) {
if (x < n) {
cin >> t[f];
x++;
}
}
else {
int ls = f << 1, rs = f << 1 | 1, mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid+1, r);
t[f] = t[ls] + t[rs];
}
}


int target, inc;
void update(int f, int l, int r) {
if (l == r) {
if (l == target) {
t[f] += inc;
}
}
else {
int ls = f << 1, rs = f << 1 | 1, mid = l + r >> 1;
if (target > mid)
update(rs, mid+1, r);
else
update(ls, l, mid);
t[f] = t[ls] + t[rs];
}
}

int target_l, target_r;
long long query(int f, int l, int r) {
if (l == r) {
if (l >= target_l && l <= target_r)
return t[f];
return 0;
}
else {
if (target_r < l || target_l > r) return 0;
int ls = f << 1, rs = f << 1 | 1, mid = l + r >> 1;
long long ans = 0;
if (target_l <= mid) {
if (target_l <= l && target_r >= mid)
ans += t[ls];
else
ans += query(ls, l, mid);
}
if (target_r > mid) {
if (target_r >= r && target_l <= mid+1)
ans += t[rs];
else
ans += query(rs, mid+1, r);
}
return ans;
}
}


int main() {
ios::sync_with_stdio(false);
cin >> n;
int r_max = 1, m;
while (r_max < n) {
r_max *= 2;
}
build(1, 1, r_max);
cin >> m;
while (m--) {
int a, b, c;
cin >> a >> b >> c;
if (a == 1) {
target = b;
inc = c;
update(1, 1, r_max);
}
else {
target_l = b; target_r = c;
cout << query(1, 1, r_max) << endl;
}
}

}

评论无需登录,可以匿名,欢迎评论!