前言
友链:zhk 的题解
但是我觉得他这篇里面提的有点简单(主要是没给代码),于是我自己来写一下~
题意简述
zps 是又可爱又傻的女孩子!于是她决定自己治疗她的脑子
zps 的垃圾脑子是一个长度为 $n$ 的序列,每个位置用 $1$ 表示这里有脑组织,$0$ 表示有脑洞(没有脑组织)。初始时全部正常。支持操作若干:
0 l r
zps 在 $[l,r]$ 之间所有脑组织都挖掉
1 l0 r0 l1 r1
zps 把 $[l_0,r_0]$ 中的脑组织都挖出来,假设有 $K$ 个,那么她会用这些脑洞来填补 $[l_1,r_1]$ 中从左到右前 $K$ 个脑洞。如果还有剩下的脑组织,她会选择直接扔掉
3 l r
询问区间 $[l,r]$ 中,最长连续脑洞长度。
$1\le n,m\le 2\times 10^5$
思路框架
线段树维护。我们整理一下需要哪些操作。
对于 $0$ 操作,我们需要区间覆盖操作
对于 $1$ 操作,我们需要求出 $[l_0,r_0]$ 中的脑洞个数 $K$(即维护区间和 $S$),把这一段区间全都覆盖为 $0$,然后还要把 $l_1,r_1$ 的前 $k$ 个脑洞变成脑组织。
对于 $2$ 操作,我们要支持维护区间的最大连续长度操作。
查询
要维护区间脑洞个数 $S$,然后要维护最长左连续脑洞长度 $LC$,右连续脑洞长度 $RC$,还有一个最长连续脑洞长度 $X$。
$S$ 就是左右加起来,显然。
如果左儿子的 $LC$ 等于左儿子的长度,那么我们的 $LC$ 跨过整个左半边再加上右儿子的 $LC$。否则 $LC$ 等于左儿子的 $LC$。
$RC$ 和 $LC$ 类似的,就是判一下能不能跨过整个右半边。
$X$ 就等于左右儿子 $X$ 的最大值,再和 左 $RC$ 加上右 $LC$ 取 $\max$。
我们把每个线段树节点封装成一个 struct
,然后重载运算符来实现这个合并。
修改
区间覆盖
我们打一个 $C$ 标记 (C=Cover
)。然后每次我们先打一下 $C$ 标记,然后如果覆盖的是 $0$(脑洞),$S=LC=RC=X=R-L+1$。否则 $S=LC=RC=X=0$。
区间填充前 k 个
把区间分成左右两块,设左半边的脑洞个数为 $lson$。
如果 $k<=lson$,那么只在左边填即可。
否则我们就把左半区间整个覆盖上 $1$ (脑组织),然后在右半边填充 $k-lson$ 个。
线段树上查找的边界为,当:
- 当前区间完全被查询区间覆盖
- (且)$k>=S$
(这种情况显然是直接整个区间覆盖上 $1$ 就行了)
为了方便写代码,我们填充完 一段区间后,函数返回一个整数,表示成功填充了多少个。 (就是有多少挖出来的脑组织没有被扔掉)。后面就会知道它为啥好写了。
代码
1 |
|