title: 线段树-学习
date: 2019-08-02 10:03:56
tags: NULL
前言:线段树是一种二叉搜索树,能通关TA实现修改、区间查询等功能……
( 相信大家都懂的……)
好吧,在这里,我们就来介绍线段树的单点修改、区间修改以及区间查询的方法。
单点修改,区间查询
Emmmmmm 这算是学习线段树的第一步了吧……
_为什么要用线段树去干这件事情呢?
你会发现,如果你直接暴力去查询一个区间 [l,r]
的和,那么这样做的时间复杂度将会使O(n)的;但是,如果你用线段树去实现这一过程,那么时间复杂度将会降成O(log n)。 _
接下来我们就来讲算法的原理。
既然线段树被称为“树”,自然是一种树状的数据结构。它的每一个节点都储存了某一个区间的信息。
它的结构如图所示:
进行修改时,我们需要更新指定修改节点已经所以与其相关的区间(即包含此节点的所有区间),查询时需查询的区间的值可以有其内部的几个区间的值拼起来得到。
代码实现:
1 |
|
想做模板题请戳这里
(请忽略题目名字,并不是我弄错了,一个模板题的潜力是无穷的)
区间修改,区间查询
其实区间修改与单点修改之间只差了一个lazy标记……
如果你用多次的单点修改来完成区间修改,那么复杂度将会是O(nlogn),显然还不如你直接修改一个数组快qwq……
所以在这个紧急关头,你需要一个lazy标记去拯救你。
对于每次区间修改,我们还是从根节点开始找每一个区间,若当前区间[l,r]
被需要修改的区间[x,y]
完全包含,那么在更新此区间的值的同时,我们还要更新lazy标记,表示该节点的两个子节点需要进行一个大小为lazy的值的修改,但是现在还没有进行。当你打完lazy标记以后,在此次修改中,你就不必再去观该节点的子树了。
那么,既然我们打了lazy标记,那么以后肯定还是需要让它起作用的。我们在每次修改和查询过程中,若遍历到某点时,该点的lazy标记不为0,则把标记下放(即根据该节点的lazy标记值去修改其子节点的值,并把该节点的lazy加到其子节点的lazy上。注意,lazy的是加过去,而不是直接覆盖!在标记下放完以后,不要忘了把该节点的lazy标记清空)。
附一下代码:
1 |
|