为什么要使用线段树?
对于有一类问题,我们关心的是线段(或者区间)
最经典的线段树问题:区间染色
有一面墙,长度为 n n n,每次选择一段墙进行染色, m m m次操作后,可以看见多少种颜色? m m m次操作后,可以在区间 [ i , j ] [i,j] [i,j]内看见多少种颜色?
使用数组实现 | |
---|---|
染色操作(更新区间) | O ( n ) O(n) O(n) |
查询操作(查询区间) | O ( n ) O(n) O(n) |
另一类经典问题:区间查询,查询一个区间 [ i , j ] [i,j] [i,j]的最大值,最小值,或者区间数字和
实质:基于区间的统计查询
例如,对于某一电商网站,查询2021年注册用户中消费最高的用户?消费最小的用户?学习时间最长的用户?
使用数组实现 | 使用线段树实现 | |
---|---|---|
更新 | O ( n ) O(n) O(n) | O ( l o g n ) O(logn) O(logn) |
查询 | O ( n ) O(n) O(n) | O ( l o g n ) O(logn) O(logn) |
将线段树抽象出来,就是解决如下问题:对于给定区间
- 更新:更新区间中一个元素或者一个区间的值
- 查询:查询一个区间 [ i , j ] [i,j] [i,j]的最大值、最小值或者区间和
什么是线段树(SegmentTree)?
线段树,也称区间树,是一种二叉搜索树,线段树的每个结点都存储了一个区间
从上图可以看出:
- 线段树中的每个节点都代表一个区间(可以理解为线段),每个节点维护的是父亲的区间二等分后的其中一个子区间
- 线段树具有唯一的根节点,根节点维护的是整个区间,代表的区间是整个统计范围
- 线段树的每个叶子节点都代表一个长度为 1 1 1的元区间
- 对于 每个内部节点 [ l , r ] [l,r] [l,