线段树

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
线段树略解
如上图所示的线段树维护 [1,10][1,10] 区间。每个节点上的区间表示该节点维护的区间。

线段树的时间复杂度 O(logN)O(\log N)(建树复杂度为 O(N)O(N)),空间复杂度 T(N)T(N)

单点修改操作

从根节点开始,选择涵盖目标节点的儿子往下跳,直到找到目标节点。修改数值,回溯更新数值。
线段树略解
如图所示,红色路径是更新 7 号节点的路径图。

区间查询操作

设节点 xx 维护的区间是 [x.l,x.r][x.l,x.r],左儿子、右儿子分别是 x.ls,x.rsx.ls,x.rs

不难发现,当询问区间恰好为 [x.l,x.r][x.l,x.r] 时,答案即为 x.dx.d

那如果不是呢?使用分治思想,将这个任务传给 xx 的两个儿子,再从儿子那里接受答案。重复以上操作,直到询问被回答。

线段树略解
举个例子。假设我们询问 [4,9][4,9] 这个区间。

我们现在在 [1,10][1,10],发现这个问题需要左儿子和右儿子一起帮忙才能回答,所以访问两个儿子。

对于 [1,5][1,5],发现右儿子就是答案的一部分,返回右儿子的 dd
对于 [6,10][6,10],左儿子和右儿子一起帮忙;

对于 [6,8][6,8],发现该点就是答案的一部分,返回该点的 dd
对于 [9,10][9,10],发现左儿子是答案的一部分,返回左儿子的 dd

这个问题就这样被回答了。

如上图所示,绿色的点表示需要遍历儿子才能回答问题;黄色的节点表示直接返回该点数值;红色边是经过的边。


至此,我们已经学会使用线段树解决 单点修改、区间查询 问题了。

区间修改、单点查询问题

例题 1 您需要写一个数据结构,维护一个序列 aa,支持以下操作:

  1. a[l],a[l+1],...,a[r]a[l],a[l+1],...,a[r] 的值加 dd
  2. 查询 a[x]a[x] 的值。

考虑将此类问题转化成我们已经学会的“单点修改、区间查询问题”。

我们发现,给一区间内的所有数加 dd 时,区间内相邻两数之差不变。所以区间加一个数等价于 修改边界处的差

c[i]=a[i]a[i1],a[0]=0c[i]=a[i]-a[i-1],a[0]=0,不难发现a[x]=i=1xc[i]a[x]=\sum_{i=1}^{x}{c[i]}

所以,查询一个数 a[x]a[x] 就被转化成求 cc 数组的前缀和(连续的)。


那如果是区间修改、区间查询呢?

区间修改操作

回顾区间查询的过程。
线段树略解
总结发现,优化时间复杂度的方法是 不走到叶子节点,在非叶节点结束本次查询

不妨尝试在区间修改中应用这个策略。与查询类似,我们给每个点设置一个值 lazylazy,表示这个节点维护的区间的每个点共有的数值。比如,给 [1,10][1,10] 里的每个数加上 dd,那么我们可以给 [1,10][1,10] 这个点的 lazylazy1010

查询时,如果该节点是绿色的,则将他的 lazylazy 值下发给他的儿子。就像这样:

线段树略解
如果该节点是黄色的,直接累加 lazylazy 对答案的贡献,也就是 lazy×(rl+1)lazy\times(r-l+1)


我们已经粗略介绍了线段树的基本操作。下面我们来看几道例题。



例题 2 已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上x
  2. 求出某区间每一个数的和

区间修改、区间查询的线段树。


例题 3

一棵树上有 nn 个节点,编号分别为 11nn,每个节点都有一个权值 ww

我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t :把结点 uu 的权值改为 tt
II. QMAX u v:询问从点 uu 到点 vv 的路径上的节点的最大权值;
III. QSUM u v:询问从点 uu 到点 vv 的路径上的节点的权值和。

先把这棵树按 dfsdfs 序排列,拍成一个序列。这样,我们便发现:树上两点的路径在序列上是若干段的连续序列。
线段树略解
使用树链剖分 + 线段树维护即可。


例题 3 请求你维护一个数列,要求提供以下两种操作:

  1. 查询当前数列中末尾 LL 个数中的最大的数,并输出这个数的值。
  2. nn 加上 tt,其中 tt 是最近一次查询操作的答案(如果还未执行过查询操作,则 t=0t=0),并将所得结果对一个固定的常数 DD 取模,将所得答案插入到数列的末尾。

记录一下现在队列的长度即可。详见这儿


(未完待续 To Be Continued)

相关文章:

  • 2021-12-07
  • 2021-05-25
  • 2021-09-30
  • 2021-09-08
  • 2021-07-15
  • 2021-12-04
  • 2021-11-05
猜你喜欢
  • 2021-08-21
  • 2021-08-11
  • 2021-07-19
  • 2021-11-21
相关资源
相似解决方案