线段树区间合并....模版

区间合并是一类问题的统称,种类很多,但在这篇博客中只需实现以下操作即可: 
有一个01串,你有三种操作:

  • 1.将[a, b]中的所有数字改成0
  • 2.将[a, b]中的所有数字改成1
  • 3.询问[a, b]中最长连续的1的长度是多少

前两种操作其实可以算作一个操作,重点在于如何高效地解决第三种操作。 
虽说平衡树也可以解决这类问题,但是这里我们使用线段树来解决。


这是一个经典的老套路

线段树维护四个值(可以缩成三个,使用第四个是为了加强程序的可读性),分别是:

  • lsum记录该区间左端点开始的最长连续的值为1区间
  • rsum记录该区间右端点开始的最长连续的值为1区间
  • sum记录该区间内最长连续的值为1的区间
  • color形象解释就是记录区间的“颜色”,具体操作是当这个区间全部是1时color置1,全部为0时color置0,否则置-1。在pushup()的时候会用到。

接下来来讲讲具体的操作

首先是重中之重pushup()

这里博主有点懒,就不画图了,相信听了讲解自己脑补一下也是能搞懂的(听起来真的很简单~~)。 
开始假设当前节点为this,其左儿子为lc,右儿子为rc,且lc,rc中四个值均准确无误,接下来要对this节点做pushup()操作。 
分步骤讨论:

  • 1、计算lsum 
    脑补一下,当lc的color为1时(也就是说左儿子结点全部由1组成),那么lsum就是lc的lsum(实际上lsum,rsum,sum的值都是左儿子结点的区间长度,换一下也没有什么大的差别)加上rc的lsum。否则直接赋值为lc−>lsum。
  • 2、计算rsum
    与计算lsum的方法类似,当rc的color为1时,那么rsum就是rc的rsum加上lc的rsum。否则直接赋值为rc−>rsum。
  • 3、计算sum
    这应该很好想,就直接在lc−>sum,rc−>sum,lc−>rsum+rc−>lsum中间取个max就可以了,其中最后一个有点特殊,想想也挺简单,因为lc−>rsum和rc−>lsum中所记录的区间是连续的(看看定义就知道了)。
  • 4.计算color
    有了前面的经验,这个应该很简单,直接给出,脑补也不困难。 

      if(sum == 0) color = 0; else if(sum == r - l + 1) color = 1; else if(0 < sum < r - l + 1) color = -1;

转载自:https://blog.csdn.net/Diogenes_/article/details/80471916

猜你喜欢

转载自blog.csdn.net/no_o_ac/article/details/81211453