线段树

线段树(Segment Tree)是一种用于解决区间查询问题的数据结构。它可以高效地执行区间修改和查询操作。 支持区间查询 (\(Ologn\)) 和单点修改 (\(Ologn\))

Code

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
struct Info {
i64 sum, min, max;
bool skip;
Info(int x = 0) : sum(x), min(sum), max(sum), skip(false) {}
friend Info operator+(const Info &a, const Info &b) {
Info c;
c.sum = a.sum + b.sum;
c.min = std::min(a.min, b.min);
c.max = std::max(a.max, b.max);
return c;
}
};
struct SegTree {
const int n;
const std::plus<Info> merge;
std::vector<Info> info;
constexpr int ls(int p) const { return 2 * p + 0; }
constexpr int rs(int p) const { return 2 * p + 1; }
SegTree(int n) : n(n), merge(std::plus<Info>()), info(4 << std::__lg(n)) {}
SegTree(std::vector<Info> init) : SegTree(init.size()) {
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init[l];
return;
}
int m = (l + r) / 2;
build(ls(p), l, m);
build(rs(p), m, r);
pull(p);
};
build(1, 0, n);
}
void pull(int p) { info[p] = merge(info[ls(p)], info[rs(p)]); }
void range_modify(int p, int l, int r, int x, int y, const Info &v) {
if (l >= y || r <= x || info[p].skip) {
return;
}
if (x <= l && r <= y && r - l == 1) {
info[p] = v;
return;
}
int m = (l + r) / 2;
range_modify(ls(p), l, m, x, y, v);
range_modify(rs(p), m, r, x, y, v);
pull(p);
}
/// @brief modify for [l, r)
void range_modify(int l, int r, const Info &v) {
range_modify(1, 0, n, l, r, v);
}
Info range_query(int p, int l, int r, int x, int y) {
if (l >= y || r <= x) {
return Info();
}
if (x <= l && r <= y) {
return info[p];
}
int m = (l + r) / 2;
return merge(range_query(ls(p), l, m, x, y),
range_query(rs(p), m, r, x, y));
}
/// @brief query for [l, r)
Info range_query(int l, int r) { return range_query(1, 0, n, l, r); }
};

使用注意事项:

  • 所有的区间均为左闭右开, [l, r)