【线段树】线段树模板
2020-06-17 19:06:00 # ACM

递归

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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <bits/stdc++.h>
#define LL long long
#define Pi acos(-1.0)
#define INF 2147483646
#define eps 1e-9
#define MS 100009
#define mss 17
using namespace std;
// Notice the data size

LL n; // 记录原数组个数
LL a[MS]; // 存原数组
LL p[MS*4]; // 数组实现树形结构 ,每一个节点对应一段区间
LL la[MS*4]; // 懒惰标记

void input() {
// 存储原数组
for(int i=1; i<=n; i++) cin >> a[i];
}

// 向上更新信息
void push_up(LL rt) {
p[rt] = p[rt<<1] + p[rt<<1|1];
}

// 下推标记
void push_down(LL rt, LL nl, LL nr) {
// 如果被标记
if(la[rt]){
// 下推标记
la[rt<<1] = la[rt<<1] + la[rt];
la[rt<<1|1] = la[rt<<1|1] + la[rt];
// 更新左右孩子信息
p[rt<<1] = p[rt<<1] + nl*la[rt];
p[rt<<1|1] = p[rt<<1|1] + nr*la[rt];
// 清除标记
la[rt] = 0;
}
}

// 建树
void build(LL l, LL r, LL rt) {
if(l == r){
// 在 *rt* 节点存储数据
p[rt] = a[l];
return;
}
LL m = (l+r)/2;
// 左右递归 寻找最后的叶子
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
// 向上更新信息
push_up(rt);
}

// 区间修改 (+)
void section_revise(LL L, LL R, LL l, LL r, LL x, LL rt) {
if(L<=l && r<=R){
// 修改该节点对应区间的值
p[rt] = p[rt] + x*(r-l+1);
// 修改懒惰标记
la[rt] = la[rt] + x;
return;
}
LL m = (l+r)/2;
// 下推标记
// 参数:节点, 左,右孩子元素个数
push_down(rt,m-l+1,r-m);
// 左右递归 ,寻找包含区间
if(m>=L) section_revise(L,R,l,m,x,rt<<1);
if(m< R) section_revise(L,R,m+1,r,x,rt<<1|1);
// 向上更新信息
push_up(rt);
}

// 区间求和
LL section_sum(LL L, LL R, LL l, LL r, LL rt) {
// 若查询到包含区间
if(L<=l && r<=R){
return p[rt];
}
LL m = (l+r)/2;
// 下推标记
push_down(rt,m-l+1,r-m);
// 记录答案
LL ans = 0;
if(m>=L) ans += section_sum(L,R,l,m,rt<<1);
if(m< R) ans += section_sum(L,R,m+1,r,rt<<1|1);
return ans;
}

// 数组现状输出
void output(LL l, LL r, LL rt){
if(l == r){
cout << p[rt] << " ";
return;
}
LL m = (l+r)/2;
// 下推标记
push_down(rt,m-l+1,r-m);
// 左右递归 寻找最后的叶子
output(l,m,rt<<1);
output(m+1,r,rt<<1|1);

}

int main() {
// 输入数据并建树
cin >> n;
input();
build(1,n,1);
// 区间修改
LL l ,r ,x;
cin >> l >> r >> x;
section_revise(l,r,1,n,x,1);
// 输出修改后结果
output(1,n,1);
cout << endl;
// 区间求和
cin >> l >> r;
cout << section_sum(l,r,1,n,1) << endl;


return 0;
}
Prev
2020-06-17 19:06:00 # ACM
Next