区间合并是一类问题的统称,种类很多,但在这篇博客中只需实现以下操作即可:
有一个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