更优雅的线段树

线段树原理非常简单,但如何优雅的实现却是一个问题

线段树简介

线段树就是把一个序列原有 nn 个点扩充为 nlognn\log n 个点,保持一定结构进行加速

每个点有

  • 自己管辖的区域
  • 两个拼起来是自己的子节点( self=lsonrsonself = lson \cup rson
  • 子节点不交( lsonrson=lson \cap rson = \varnothing
  • 可以快速的区间合并
Segment Tree By yutianx

实现

个人喜欢写结构体和指针

自定义一个 null 可能是避免代码冗长的一个办法(否则到处判 == NULL

但是这样的话好像有些函数得分开写

查询区间 [L,R][L,R] 用全局变量存可以减少参数传递

P3372 【模板】线段树 1

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
#include <iostream>
typedef long long ll;
const int N = 100000;

struct Node {
ll sum, tag;
int l, r;
Node *ls, *rs;
inline int len();
void maintain();
void pushdown();
ll query();
void add();
Node *build(int, int);
void print();
};
Node T[N * 4];
Node *null;
int cnt = 1, L, R, X;

int Node::len() { return r - l + 1; }
void Node::maintain() { sum = ls->sum + rs->sum; }
void Node::pushdown() {
ls->tag += tag, rs->tag += tag;
ls->sum += ls->len() * tag, rs->sum += rs->len() * tag;
tag = 0;
null->sum = null->tag = 0;
}
ll Node::query() {
if (L <= l && r <= R) return sum;
if (r < L || R < l) return 0;
pushdown();
return ls->query() + rs->query();
}
void Node::add() {
if (r < L || R < l) return;
if (L <= l && r <= R)
tag += X, sum += len() * X;
else
pushdown(), ls->add(), rs->add(), maintain();
}
Node *Node::build(int l, int r) {
Node *ret = &T[cnt++];
ret->l = l, ret->r = r, ret->ls = ret->rs = null;
if (l == r)
cin >> ret->sum;
else {
int mid = (l + r) / 2;
ret->ls = build(l, mid), ret->rs = build(mid + 1, r);
ret->maintain();
}
return ret;
}

void Node::print() {
if (this == null) return;
cerr << l << ' ' << r << ' ' << sum << ' ' << tag << endl;
ls->print(), rs->print();
}

int main() {
std::ios::sync_with_stdio(false);
cout.tie(0);
int n, m;
null = T;
null->ls = null->rs = null;
cin >> n >> m;
Node *rt = null->build(1, n);
L = 1, R = n;
while (m--) {
int opt;
cin >> opt >> L >> R;
if (opt == 1) {
cin >> X;
rt->add();
} else
cout << rt->query() << '\n';
}
return 0;
}
作者

Gesrua

发布于

2019-02-10

更新于

2020-11-21

许可协议