数据结构学习笔记
势能均摊
对于一些难以维护的区间操作,我们可以考虑一个数被操作的次数,对于某些变换,可能操作次数非常小,所以我们只进行有用的操作,复杂度仍然是正确的。
例如区间开根,如果值域是
这种问题的维护方式通常有两种:一种是使用并查集,如果一个数
上面这种东西的局限性在于难以快速得到区间的某些信息,当然可以上个数据结构,但是这样就不如在线段树上直接做,到叶节点后暴力修改。但是有的区间因为有一个数还能动就被遍历到了,造成了一定的浪费,但一个数最多浪费
那么什么操作有这种性质呢?常见的有
甚至或操作这种也是可以的,因为每次操作只会把原来是
例题:
P9989 [Ynoi Easy Round 2023] TEST_69
对于
正难则反,一个区间不用操作首先要要求
注意到
线段树合并
例题:
P3224 [HNOI2012] 永无乡
简单题,直接用动态开点权值线段树维护每个点目前的情况,并查集维护连通性。合并就是并查集的两个根合并即可。
因为查询时只用到并查集的根,这个根必然没被合并,所以每次这个根上的信息都是对的。
是排列,所以直接记下
P3899 [湖南集训] 更为厉害
首先
那这样事情就很好描述了,
又知道
对于每个
当
当
一个需要注意的点是如果你直接把两棵树合并的话树中的信息会改变,但我们是进行完所有合并后再查询,所以说这样会导致答案的错误,解决方案就是每次合并也新建节点,只是这样节点数会翻倍。
接下来就是比较牛逼的东西了
例题:
P5298 [PKUWC2018] Minimax
首先将权值离散化,然后概率乘上
考虑 dp,设
显然,将权值排序后答案就是
对于
分别考虑是取最大值还是最小值,以及取得是哪个数,可以得到:
考虑用线段树合并维护,那么左右两棵树分别要乘上一些不同的东西,计算即可。
然后这里的点在于我们不在注意线段树代表的区间,而只关心两个节点的存在情况合并,这样并不会改变复杂度,到了一个空节点对另一个节点打上
线段树每次走区间的时候,就恰好帮我们维护了前后缀和,同时因为权值互不相同,若一边的
KTT
例题:
The Third Grace
首先考虑 dp。设
初值可以直接令
转移就考虑上一个点选的是
考虑这样对区间
所以得到转移方程为
这样是很难优化的。考虑换一个角度,转为计算每个
那么考虑从
那么最终每个
-
对于区间
, 。 -
单点修改一个点的
。 -
查询区间(其实也可以全局)最大值。
考虑使用 KTT,初始时可以将
注意 KTT 的
树套树
例题:
CF1093E Intersection of Permutations
出现了两个排列的对应,考虑算出每个
那么现在我们要做的就是:
- 查询
的 的个数。 - 交换
。
外层树状数组,内层动态开点权值线段树维护即可。交换操作相当于对某个位置某个值的加减。
注意内存回收,对于某个节点,如果它维护的权值数量变成了
因为每个时刻每个
P3759 [TJOI2017] 不勤劳的图书管理员
题意是给你序列
首先
考虑交换产生的影响,这里假设
我们令
- 若
,考虑原先 的大小关系。
若
,那么原先 与 均不构成逆序关系,交换后构成了两组逆序关系,答案增加了 。
若,那么已经构成的逆序关系被消除,答案减少 。
若,显然没有影响。
-
若
,原先 与左侧的 构成了逆序关系,交换后与 构成了逆序关系,答案由 变为了 。 -
若
,原先 与右侧的 构成了逆序关系,交换后与 构成了逆序关系,答案由 变为了 。
最后再更新一下
为了快速维护以上操作,我们需要查询某个下标区间中
写的时候注意区分
平衡树
例题:
CF85D Sum of Medians
考虑平衡树,记 pushup
里,此时仅需考虑
我们都知道,一棵平衡树的中序遍历就是它的关键字顺序,所以当前
那么可以得到,
P4008 [NOI2003] 文本编辑器
写一个按照大小分裂的 FHQ treap 就好了。可以记当前的指针
Link Cut Tree
LCT 的核心内容在于 access 操作,其打通一条实链的操作使其 LCT 有着灵活多变的结构和极其强大的功能。
一些应用:
维护生成树
维护子树信息
考虑一个点有的儿子:除了一个实儿子,还有若干个虚儿子,那么我们要同时维护实儿子和虚儿子的信息,实儿子是好做的,splay 可以帮我们维护,那么虚儿子怎么做呢?
例题:
[ABC350G] Mediator
考虑 LCT,首先判断
主席树
例题:
CF226E Noble Knight's Path
先树剖,然后考虑对操作的时间建主席树,那么修改直接操作即可,考虑查询。
这里,我们对一条重链上的可以使用的城堡计数有两条限制,主席树可以帮我们解决掉时间的限制,但是还有区间的限制怎么办呢。
一开始应该会想到像区间第
那么考虑先在主席树上做一次区间查询,然后对查询到的叶子依次通过差分+二分找第
注意
cdq 分治
例题:
P4169 [Violet] 天使玩偶/SJY摆棋子
考虑没有修改怎么做。
那么就是,给你
分类讨论:
-
,求 。 -
,求 。 -
,求 。 -
,求 。
把所有的询问和修改按照
现在加上修改。
使用 cdq 分治,设计函数
先分治两边,然后问题就在计算
把左右两部分的点按照
时间复杂度
[BalkanOI2007] Mokia 摩基亚
同样考虑不带修改。
那么可以把一个询问拆成四个,即
带上修改,就使用 cdq 分治即可。
离线扫描线技巧
例题:
P3863 序列
考虑
现在问题变为了区间操作,把区间操作用差分拆成
对于一个查询
更通俗一点的说法是:我们就是维护时间轴,然后从
那么我们需要一个数据结构,支持区间加,查询
[SCOI2015] 情报传递
考虑一个点被标记的时间
把修改拉出来,询问按
笛卡尔树
【梦熊 2025 炼石计划】 C.昔在、今在、永在的剧目
赛时想的是对于一个 OR 和超过
考虑另一种贪心:对于最大值不变的区间,肯定是越长越优,这样就不用考虑
以下的合法均只考虑 OR 的限制。
接下来考虑修改只会让一些不合法的区间变成合法的,因为 OR 不会变小。
同时,对于大区间分出的小区间,如果小区间合法,那么大区间一定也合法。所以某一时刻合法的区间在笛卡尔树上构成了一个包含根的连通块或不存在合法的区间。进行修改只会让连通块往下面扩展。
一次修改会影响到哪些点呢?考虑笛卡尔树上代表的区间包含
我们需要一些数据结构,检验区件是否合法用 SGT,查询后缀 min 用 BIT。
时间复杂度
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律