线段树和树状数组(1)
Preview:
终于到了喜闻乐见的线段树了,因为其灵活度较高,基本框架固定,深受像我这样喜欢水题的人的喜爱。
而至于为什么文章名叫“线段树和树状数组”呢,实际上我们可以把树状数组看做成没有右儿子的线段树,然后加的时候是直接进行的 pushup
,然后这样树状数组是否就清晰多了呢?
板子:
因为本人太懒了,所以懒得打板子了。
详情可见树状数组 1、2,线段树 1、2,普通平衡树,可持久化线段树 1、2,线段树 3。
例题:
Preface:
为什么会有这一栏呢,原因是因为自己太懒了,懒得打代码,然后如果有什么题自己能直接口胡出来就写到这里口胡。
P2023 [AHOI2009] 维护序列(线段树 2):
考虑线段树,维护两个 tag
,加和乘。
乘的时候别忘了给加的 tag
也乘上。
千万别忘了取模。
先乘后加。
P1471 方差:
线段树,操作 1、2 都是经典操作,这里不多赘述。
重点考虑操作 3。
听起来不想很能维护的样子,但是这里面有个
对方差的公式拆个式子:
所以我们可以清楚地看到,对于方差,我们只需要维护其区间和 sum
和平方和 sqrsum
即可。
然后就是注意精度。
P6327 区间加区间sin和:
我表示差角公式直接套版。
CDQZ Challenge 5:
有两种思路,先说第一种:
对于操作
至于操作
第二种是机房
对于一个区间,我们维护两个值,分别是两两相乘的值和区间和,对于区间的合并,我们则有:
然后就做完了,毕竟是单点改,所以修改操作也是
以上两种的时间复杂度都是
PS:更多关于 CDQZ Challenge 的内容,可以看我的这篇博客
P4513 小白逛公园:
考虑用线段树维护。
我们可以发现一件事情,若我们要合并两个区间,那么对于合并区间内的区间最大值来说,它要么是左区间最大值,要么是右区间最大值,要么既不是左区间最大值,也不是左区间最大值。
前两类十分好想,但是最后一类该怎么办呢?
考虑一下如果不是左区间最大值,也不是右区间最大值,那么可能存在的区域只可能会是两个区间的交界处,此时我们只需要维护一个前缀最大值和后缀最大值,然后将左区间的后缀最大值和右区间的前缀最大值拼接在一起,就是第三类情况。可以得证,这种拼接方式即使第三类最大值。
综上,对于每个线段树上的节点,维护前缀最大值,后缀最大值和区间最大值即可。
剩下就是板子了。
PS:可以去尝试一下 GSS 题目,十分小清新。
P7706 「Wdsr-2.7」文文的摄影布置:
PS:上述的等价指的是方法等价
一道非常有意思的题目。
题目可以转化成如下问题:
显然,原式可以直接转化为:
证明显然。
此时,我们思考如何从子区间合并上来。
还是依照 P4513
的思路,考虑最优的答案会出现在哪里。
则显然,父区间的答案只会在左区间答案、右区间答案、区间交界处答案取到。
左右区间的答案可以直接维护,但是区间交界处我们就得需要分类讨论了。
首先,因为答案分散在两个区间,所以
此时,对于两个子区间,就需要维护如下式子:
然后你就又会发现,诶
于是设
然后考虑怎么维护。
于是又双叒叕可以参考 P4513
的思路,发现对于
则显然,父区间的答案只会在左区间答案、右区间答案、区间交界处(?)答案取到。
这里的区间交界处是什么意思呢,即
所以对于父区间
所以,对于
最后就是套板子了。
P5278 算术天才⑨与等差数列
对这个题目,有两种思路:
Solution 1:
考虑 Hash
,可以参考此题弱化版 P3792 由乃与大母神原型和偶像崇拜
。
Hash
的值可以是区间和,区间平方和,区间立方和,反正 Hash
嘛。
PS:该做法可能会被卡掉,不过如果你可以选择多维护几个 Hash
值。
时间复杂度
Solution 2:
差分,将原问题转化为区间
至于不出现相同数字嘛,维护前驱,变成数点问题。
时间复杂度
然而可以去掉一只
时间复杂度
P4344 [SHOI2015]脑洞治疗仪:
本题两种思路:
Solution 1:
实际上当把这个
无非就是区间推平 + 区间连续段最值问题而已。
如果我们不考虑在线段树上二分,则是直接二分开始推平的位置。
时间复杂度
但是如果你会线段树上二分的
虽然
Solution 2:
珂朵莉树
没了。
P2572 [SCOI2010] 序列操作:
对,这题没啥难度,但是就是纯纯恶心人。
注意一下取反的时候也别忘了把推平的 tag
给取反就行。
P6492 [COCI2010-2011#6] STEP:
小白逛公园的
不过需要考虑合并可行性。
P2894 [USACO08FEB] Hotel G:
感觉很像 P4344
,不过就是如果住不下就直接不住了,P4344
是住不下就舍掉一部分而已。
CF438D The Child and Sequence
其他两个操作都很简单,重点来考虑取模操作。
首先考虑每次取模操作所带来的影响,会发现实际上每次取模之后,所有数要么缩小,要么不变。
考虑维护区间最大值,如果区间最大值大于等于待取模数我们就暴力往下修改,直到某个区间的最大值小于待取模数或者到达叶子节点时再停下。
乍一听好像时间复杂度十分不可取,实际上均摊一下复杂度是
CF240F TorCoder
使用这个
(或者说是直接用来骗分)
思考一下,对于构造回文串,我们只需要分两类讨论:
-
当需要构造的长度为偶数时,我们需要每一种颜色的数量都为偶数。
-
当需要构造的长度为奇数时,我们需要有一种颜色的数量为奇数,其余都为偶数。
然后就是开
注意空间。
CF431E Chemistry Experiment
看到 check
部分,使得
本题维护一个值域线段树,动态开点,支持区间和和值域区间有效个数和。
考虑二分答案
注意精度。
P1438 无聊的数列
emm……感觉这个
考虑对原序列差分,因为是单点查询,所以差分后就变成区间查询了。
然后就是考虑等差数列修改,因为等差,所以相当于是区间加,然后再在
哦对了,别忘了在
PS:是不是树状数组也能做啊/yiw
CF992E Nastya and King-Shamans
考虑将原序列转化为前缀和,则此时单点修改就变成了在前缀和序列上区间修改。
然后考虑用 rmq
线段树维护原序列与前缀和的差值,此时,每次单点修改就变成了区间减和单点加。
查询就向下递归区间最大值
为什么复杂度是正确的呢?
因为题目保证,任何时候
时间复杂度
可能需要减减常数,这个时限不是很健康。
CF1000F One Occurrence:
咕咕咕,我是鸽子
CF1149C Tree Generator™
在讲作法之前,我不得不承认,刚开始的时候,确实被这道题给耍了,这个傻子刚开始满脑子想的都是
这题我认为是诈骗题的 master
(也可能只有我这么傻,ε=(´ο`*)))唉)
将所有左括号看做成
如果你认为是最大子段和
如果考虑最大子段和的话,你会发现,你给无根树定死了根节点,但是像如下样例的情况你就处理不了了:
输入:
((()))((()))
最大子段和 + 1:
3
答案:
7
所以再次观察括号序列,发现树的直径就是括号序列的最长去匹配区间。
然后我们可以发现如下
最长去匹配区间 =
然后原问题被转化成了如何求最大子段相邻区间差
考虑一下线段树怎么维护(大家好,我喜欢暴力数据结构……)这个看起来十分难以维护的东西。
这里我使用的是逆向分析法(具体思路可以参考一下 P7706):
首先,考虑最终答案需要什么贡献,对于一个区间的
然后你就发现,这个最终答案的维护十分抽象,好像需要 min
和 max
,后缀子段和的 min
和 max
,前缀的 sum
。
因为剩下的维护太 naive
了,所以懒得写了。
交换操作就是单点取反,
小结
感觉这份博客的水题好像有点多了,抽时间再写个
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通