线段树知识整理


一:什么是线段树?

线段树的概念: 线段树是算法竞赛中常用的用来维护 区间信息 的数据结构。

线段树可以在 O ( l o g N ) O(logN) O(logN) 的时间复杂度内实现单点修改区间修改区间查询区间求和求区间最大值求区间最小值)等操作。


二:线段树的基本结构及空间复杂度

线段树的结构(文字解释):

  • 线段树将每个长度不为 1 1 1 的区间划分成左右两个区间递归求解,把整个线段划分为一个树形结构,
  • 线段树的操作通过合并左右两区间信息来求得该区间的信息。这种数据结构可以方便的进行大部分的区间操作。
  • 线段树为满二叉树,用一维数组存整颗树

线段树的结构(下图所示):
算法竞赛进阶指南

线段树的空间复杂度:

对于线段树最少要开4倍空间的解释:

  • 若最后一层节点都满,则该层为最后一层,有 N N N个节点,则其上面节点数为 N / 2 + N / 4 + N / 8 + . . . . . . + 1 N/2 + N/4 + N/8 + ...... + 1 N/2+N/4+N/8+......+1,此时所有节点数为 N + N / 2 + N / 4 + N / 8 + . . . . . . + 1 N + N/2 + N/4 + N/8 + ...... + 1 N+N/2+N/4+N/8+......+1 和为 2 N − 1 2N - 1 2N1
  • 若最后一层不满,即、上两图所示的情况,则倒数第二层为 N 个节点 N个节点 N个节点,除倒数第一层以外的所有层节点和为 2 N − 1 2N - 1 2N1,最后一层为 2 N 2N 2N 个节点,即、总节点为 4 N − 1 4N - 1 4N1 ,所以保险起见,线段树一律开 4 N 4N 4N 空间

三:线段树的常用操作

线段树的建树

线段树的节点关系:

  • 若该节点为 x
  • 其父节点为 x / 2等效于x >> 1
  • 左儿子为 x * 2等效于x << 1
  • 右儿子为 x * 2 + 1等效于x << 1 | 1

常用函数:

  • p u s h u p ( ) pushup() pushup()
  • p u s h d o w n ( ) pushdown() pushdown()
  • b u i l d ( ) build() build()
  • m o d i f y ( ) modify() modify()
  • q u e r y ( ) query() query()

1.pushup() 更新操作(子->父)

在介绍 b u i l d ( ) build() build() 函数之前先介绍 p u s h u p ( ) pushup() pushup() 函数;

p u s h u p ( ) pushup() pushup()函数含义为:由子节点信息更新父节点信息

例子:单点修改(求最大值,最小值等 …)


2.pushdown() 更新操作(父->子)

**俗称:**懒标记(支持区间修改)
以区间加为例:
含义: 给当前区间的所有儿子加上 add(懒标记)
如图:
在这里插入图片描述


3.build() 建树操作

建立线段树

  • 从根节点开始,一层层递归到叶子节点
  • 每递归一层调用一次 p u s h u p ( ) ( 由子节点更新父节点 ) pushup()(由子节点更新父节点) pushup()(由子节点更新父节点)

一般模板为:


函数参数为:当前区间的编号u 当前区间的左端点l 当前区间的右端点r

void build(int u, int l, int r)
{
	tr[u] = {l, r};
	if(l == r) return;
	int mid = l + r >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
	pushup(u);
}


3.modify() 修改操作

  • 单点修改操作:一直递归至叶子节点,在返回时 p u s h u p ( ) pushup() pushup() 即可
  • 区间修改操作:和 q u e r y ( ) query() query()函数 类似,每次分裂前 p u s h d o w n ( ) pushdown() pushdown() ,返回时 p u s h u p ( ) pushup() pushup()

4.query() 查询操作

以查询区间最大值为例:
其中 [ L , R ] [L, R] [L,R] 为 要查询的区间, [ T L , T R ] [T_L, T_R] [TL,TR] 为当前区间的范围

则有如下几种情况:

  1. [ L , R ] ⊃ [ T L , T R ] [L, R] \supset [T_L, T_R] [L,R][TL,TR]
  2. [ L , R ] ∩ [ T L , T R ] ≠ ∅ [L, R] \cap [T_L, T_R] \neq \varnothing [L,R][TL,TR]=
  3. [ L , R ] ∩ [ T L , T R ] = ∅ [L, R] \cap [T_L, T_R]= \varnothing [L,R][TL,TR]=

具体操作:

1. [ L , R ] ⊃ [ T L , T R ] [L, R] \supset [T_L, T_R] [L,R][TL,TR]
如图:
在这里插入图片描述
即、树中区间在我们要查询区间的内部:直接返回最大值(树中保存的信息即可)

2. [ L , R ] ∩ [ T L , T R ] ≠ ∅ [L, R] \cap [T_L, T_R] \neq \varnothing [L,R][TL,TR]=
如图:
在这里插入图片描述

包含如下几种情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结

  1. 查询区间于树中区间有交集,则递归交集的部分:左边有交集递归左边,右边有交集递归右边

  2. 一般只有两条链递归至叶子节点,时间复杂度为 O ( l o g N ) O(logN) O(logN),但 l o g N logN logN 的常数较大(比树状数组,st表等都大)

3. [ L , R ] ∩ [ T L , T R ] = ∅ [L, R] \cap [T_L, T_R]= \varnothing [L,R][TL,TR]=
不存在此种情况!!!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AC自动寄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值