You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##P6242 【模板】线段树 (吉司机线段树) 3

吉老师PPT下载

参考题解I

参考题解II

参考题解III

视频资源

HDU 5306 Gorgeous Sequence

一、题目简介

给你一个长度为 n 的序列 a。令序列 b=a

现在让你进行 m 次操作,分为 5 种:

1 l r k:将序列 a 中区间 [l,r] 的数加上 k

2 l r v:将序列 a 中区间 [l,r] 的数对 v 取最小值

3 l r:求序列 a 中区间 [l,r] 的数的和

4 l r:求序列 a 中区间 [l,r] 的数的最大值

5 l r:求序列 b 中区间 [l,r] 的数的最大值

每次操作后令 b_{i}=\max(b_{i},a_{i})

二、思路

前置知识:线段树。以及会写操作 2 以外的所有操作。

吉司机线段树模版题,考虑用线段树维护。

先引入一下 3 个概念:

  • a_i 的历史最(小/大)值a_{i} 存放过的最(小/大)的数

  • 区间最(小/大)值操作:将序列 a 中区间 [l,r] 中的数 a_{i} 变为 \min(a_i,v)\max(a_i,v),i \in [l,r]

  • 严格次大值:最大的比最大值小的值,可以理解为最大值的前驱

显然在这题中, ① b_i 就是 a_i历史最大值 ② 操作 2 就是区间最小值操作 ③ 操作 5 是求区间最大历史最大值

接下来进入正题。

容易发现这道题的瓶颈在于进行操作 2 后,无法快速更新信息。只能递归到叶子节点,然后对其取最小值。

这样写单次修改的时间复杂度就会达到惊人的 O(n)

那怎么办呢?线段树显然不能直接区间取 \min

换一个思路 : 把区间内大于 v 的数都减去一个数,使得这些数都变为 v

因为不同的数要减去不同的数才能等于 v,显然我们不能设很多 tag 来表示区间内不同的数要减去的数。

那退一步来讲,若区间内大于 v 的数只有一种,我们可以怎么做呢?

只需要维护一个 tag 就行了。

那怎样才能使得区间内大于 v 的数只有一种呢?

只需要多递归几次就行了。(啥意思?)

我们在线段树每个节点设以下 3 个变量,分别为:

  • maxn:区间最大值

  • se:区间严格次大值

  • cnt:区间最大值个数

在区间只有一种数大于 k 的时候,才能快速更新,即只能在满足 se<k<maxn 的节点上更新。

具体的,我们在进行操作 2,正在线段树上递归时,会有以下 3 种情况:

  • maxn≤v:说明这个区间的最大值小于等于 v,直接返回即可
  • se<v<maxn:说明这个区间的最大值会全部被修改成 v,但其它数和最大值的个数不变,修改后打上懒标记返回即可
  • v≤se:无法更新,继续递归

思路大致就是在线段树中递归,直到该区间大于 v 的数只有一种就更新。

总的时间复杂度: O(mlog_2n)

三、题解

首先说明,本题解主要以代码为主。个人认为代码写得很清晰,如果懂得上述思路就一定可以看懂。

先来看一下线段树每个节点需要存些什么。

  • add1:区间最大值的懒标记

  • add2:区间非最大值的懒标记

  • add3:区间最大值的懒标记的最大值

  • add4:区间非最大的值的懒标记的最大值

具体地,add3 是在未下传懒标记前最大的 add1 的值,add4 是在未下传懒标记前最大的 add2 的值。

4tag 只要理解透了,代码就一定可以看得懂。

TODO https://www.luogu.com.cn/blog/Sqrtree/solution-p6242