由于线段树在OI中的运用十分灵活,没有固定性的模板,这里就给出能够完成以下操作的线段树:1.给一段区间加上一个值
2.询问一个区间内数值的总和
$lazy-tag$是个好东西,要养成写$lazy-tag$的好习惯。
先码上一个链表版本的线段树:
链表线段树很简单(不是假的),像我这样的蒟蒻就是因为静态数组线段树写炸了才写链表线段树的。
外模板
1 | struct SegTree { |
几个构造函数(方便函数使用)1
2
3
4SegTree(int l, int r, SegTree *lc, SegTree *rc)
: l(l), r(r), lc(lc), rc(rc), sum(lc->sum + rc->sum), add(0) {} //非子结点的构造函数,自带pushup()
SegTree(int l, int r, SegTree *lc, SegTree *rc, long long sum)
: l(l), r(r), lc(lc), rc(rc), sum(sum), add(0) {} //子结点构造函数
build函数1
2
3
4
5
6
7
8static SegTree *build(int l, int r) { //静态成员函数
if (l > r) return NULL;
else if (l == r) return new SegTree(l, r, NULL, NULL, a[l]); //叶子节点构造
else {
int mid = (l + r) >> 1;
return new SegTree(l, r, build(l, mid), build(mid + 1, r)); //非叶子节点递归构造
}
}
updata1
2
3
4
5
6
7
8
9
10
11void update(int l, int r, long long rhs) {
if (l > this->r || r < this->l) return; //若当前区间和要处理的区间没有交集,就return
else if (l <= this->l && this->r <= r) cover(rhs); //当前区间和要处理的区间重合,直接覆盖标记
else {
pushdown();
lc->update(l, r, rhs); //递归
rc->update(l, r, rhs);
pushup();
}
return;
}
query1
2
3
4
5
6long long query(int l, int r) {
if (l > this->r || r < this->l) return 0;
if (l <= this->l && this->r <= r) return sum;
pushdown();
return lc->query(l, r) + rc->query(l, r); //递归统计
}
cover覆盖标记1
2
3
4void cover(long long rhs) {
add += rhs;
sum += rhs * (r - l + 1);
}
pushdown标记下传1
2
3
4
5void pushdown() {
lc->cover(add);
rc->cover(add);
add = 0;
}
pushup1
2
3void pushup() {
sum = lc->sum + rc->sum;
}
完整代码
1 | struct SegTree { |
相似的,我直接给出不带注释的数组版本的线段树(左移2位千万不要忘!!!)。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
45struct SegTree {
static const int MAXSIZE = 100000 + 5;
long long sum[MAXSIZE << 2], add[MAXSIZE << 2];
void cover(int o, int l, int r, long long rhs) {
add[o] += rhs;
sum[o] += rhs * (r - l + 1);
}
void pushdown(int o, int l, int r) {
int mid = (l + r) >> 1;
cover(o << 1, l, mid, add[o]);
cover(o << 1 | 1, mid + 1, r, add[o]);
add[o] = 0;
}
void pushup(int o) {
sum[o] = sum[o << 1] + sum[o << 1 | 1];
}
void update(int o, int l, int r, int L, int R, long long rhs) {
if (L > r || R < l) return;
else if (L <= l && r <= R) cover(o, l, r, rhs);
else {
pushdown(o, l, r);
int mid = (l + r) >> 1;
update(o << 1, l, mid, L, R, rhs);
update(o << 1 | 1, mid + 1, r, L, R, rhs);
pushup(o);
}
}
long long query(int o, int l, int r, int L, int R) {
if (L > r || R < l) return 0;
if (L <= l && r <= R) return sum[o];
pushdown(o, l, r);
int mid = (l + r) >> 1;
return query(o << 1, l, mid, L, R) + query(o << 1 | 1, mid + 1, r, L, R);
}
void build(int o, int l, int r) {
if (l > r) return;
else if (l == r) sum[o] = a[l], add[o] = 0;
else {
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
pushup(o);
}
}
};