线段树 1
操作:
- pushup: 根据子节点 更新 父节点
- eg.
sum = l.sum + r.sum
- eg.
- pushdown: 父节点的修改信息,下传到子节点
- alias: 懒标记 / 延迟标记
线段树是算法竞赛中常用的用来维护 区间信息 的数据结构
线段树可以在 \(O(logN)\) 的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作
(1) 一般用来:
- 单点修改
- 区间修改: 见下节课 "线段树-2", 这里不提
- 区间查询(即区间求和,求区间 max ,求区间 min ,区间 gcd ...)
但是,线段树所维护的信息,需要满足区间加法:
Text Only | |
---|---|
1 |
|
(2) 基础操作:
pushup(u)
pushdown(u)
build()
: 将一段区间 初始化 成线段树modify()
: 修改- 单点: 很简单
- 一段区间: 很难。要结合
pushdown()
, 懒标记
query()
(3) 存储:
- 空间开设: 如果有
n
个点, 开的空间是4n
- 存储方式: 采用
heap
存储- 一棵线段树的 root 的编号是 1
- 设一个不为根的节点编号 x ,则这个点的父节点:
x/2
(向上取整), 子节点分别是2x
和2x+1
- 父节点:
x>>1
- 左儿子:
x<<1
- 右儿子:
x<<1 | 1
表示方式:
C++ | |
---|---|
1 2 3 4 |
|
(4) 基本概念
(5) 模板:
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
注意 modify()
和 query()
是否需要 "将结果向上传递给父节点, 逐层更新"
1275 最大数¶
分析, 这个题目的两个操作等价于:
- 在某一个位置, 修改一个数 (单点修改)
- 求某个区间内的最大值
构建, tree node:
C++ | |
---|---|
1 2 3 4 5 |
|
代码:
C++ | |
---|---|
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 |
|
245 你能回答这些问题吗¶
纯模板线段树
分析, 这个题目的两个操作等价于:
- 在某一个位置, 修改一个数 (单点修改)
- 求某个区间内的"连续最大子段和"
构建, tree node:
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
考虑一下更新的方式:
(1) tmax:
C++ | |
---|---|
1 2 3 4 5 |
|
(2) lmax:
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
(3) rmax: 同理
(4) sum: sum = left_son.sum + right_son.sum
代码:
C++ | |
---|---|
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 |
|
求最大值的方法:
C++ | |
---|---|
1 2 3 4 |
|
246 区间最大公约数¶
C++ | |
---|---|
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 |
|