专栏文章
NFLS暑假专题3 可持久化数据结构,复杂分块,树套树
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioslio9
- 此快照首次捕获于
- 2025/12/03 00:28 3 个月前
- 此快照最后确认于
- 2025/12/03 00:28 3 个月前
By fishpear。远古大神,讲得好啊。
可持久化数据结构
首先是主席树,耳熟能详了属于是,考虑推广一下:
- 假如我们的数据结构是个树且不存储父节点,就能套用主席树的方法。
众所周知,平衡树难以可持久化。主要原因在于旋转操作依赖于父节点,但其实可以在递归过程中存储祖先链到一个数组,就能做到可持久化。当然没人写这玩意。
同时课件指出:fhq treap 本质上是将上述数组用递归时的系统栈存起来,也就是说两种方法是相同的。
然后是区间修改,一般来说我们得写标记永久化,但是真的不能用标记下传了吗?不是的。
最后,对于一般的数据结构也能可持久化吗?可以的,用可持久化数组即可,例子是并查集。不过会多一只 log。
同时,假如只要求回滚,拿个栈存储修改即可。
对于特定问题,存在不带 log 做法。视频链接,当然这玩意不考。
P2839 middle
经典套路:中位数无脑二分答案 。
将 设为 , 设为 。那么区间中位数 等价于区间和 。所以问题变为寻找最大区间和,这是容易的。然后用主席树存下每个 的线段树即可。。
由此提出运用可持久化的基本方法:若发现将询问离线后数据结构可解,将该数据结构可持久化便能在线了。也就是说,可持久化具有强制转在线的作用。
P4899 [IOI 2018] werewolf 狼人(无代码)
题意:无向图,多次询问从 ,变身前只能在 ,变身后只能在 ,问是否可行。
枚举变身点,问题转化为 只走 、 只走 两个连通块是否存在交集。
联想到 kruskal 重构树,分别从前往后、从后往前加入点,那么两个连通块对应两个森林上的两个子树。使用 dfs 序刻画限制,将点转化为二维数点,坐标分别是两个森林上的 dfs 序,每次询问一个矩形是否有点,主席树即可。
这题重点在于用 kruskal 重构树将连通块转化为子树、并通过 dfs 序转化为二维数点问题。主席树只是工具。
细节:kruskal 重构树按点权构建,只需将边权设为两端点编号最值即可。
P7172 [COCI 2020/2021 #3] Specijacija(无代码,要补)
题意:一棵 层的树,每一层恰有一个点有两个儿子,其它只有一个,编号从上到下、从左往右。多次询问求 。
直观想法是倍增跳 lca,问题变为对任意点求任意级祖先。为了解决这个问题,重新编号以观察性质:

从下往上,考虑每个叶子对应该层的哪个点,可以发现,是前缀 编号不变,后缀 编号减一。想到用主席树后缀减、单点查。但是点不一定是叶子,需要找到其子树内一个叶子,需支持寻找 对应下标,由于序列有序,树上二分即可。
突破点在于观察到相邻层之间节点编号变化的规律,并联想到运用主席树维护叶子每层对应祖先、以支持倍增。
QOJ970 Best Subsequence(无代码,要补)
题意:给一个数组,多次询问在 中选 个数,最小化相邻数之和(包括首尾)的最大值。
较为困难的一题。
二分答案 转判定。然后有一个套路:将 的视为 、 的视为 。那么 一定行, 一定不行, 看情况。
贪心地想,先全选 肯定不劣。直觉上很对。考虑最优解存在一个 不被选,若加入后产生 非法,那么将这个唯一存在的 去掉即可。
接下来加入 ,对于首尾和相邻 之间的 显然取最小的,判断能否加入即可。
考虑用数据结构加速这个过程,考虑 从小到大,每次修改 变成 。考虑相邻 构成的段,那么总共会有 次区间分裂,对于不分裂的区间,会在某个时间由不可选变为可选,拿一个线段树捕捉这些点即可。对于分裂的区间,我们直接取出最小值并标记是否可选即可。
然后用主席树维护即可,。
这题主要是想到按 分类,然后贪心,并用数据结构进行优化,用可持久化支持二分。
分块
技巧性很强,见例题。
P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I(无代码,要补)
题意:求区间逆序对,强制在线,。
大力分块取块长 。
考虑整块与整块,提前排序每次做归并,预处理整块两两间的逆序对数,。
考虑散块内部,必然是前后缀,用插排即可,。
考虑散块与整块,相当于求一个数与一个整块,只需在整块与整块部分记录即可。查询 。
考虑散块与散块,从整块排序结果中,提取散块排序后的结果,然后直接归并,查询 。
考虑短区间 在整块 中,考虑容斥,可以直接提取出 三部分排序后结果,然后归并即可算出三部分互相的逆序对数。单次也是 。
总的就是优美的 。
这题揭示了分块的基本方法:整块、散块分开讨论。分块一般带 log 是好做的,若要去 log 则需精细实现,技巧性非常强。
CF453E Little Pony and Lord Tirek(无代码,要补)
题意: 个数初始为 ,每秒增长 ,上限为 。需支持:时间增长 ;求区间和并马上清空区间。。
可以基于颜色段 ,不讨论。
分块,将被不完全推平的段称为特殊段,初始时均为特殊段。散块暴力计算即可。
每次推平时,对特殊段进行暴力计算,并对新产生的特殊段暴力更新。那么特殊段总数为 ,且除首尾外特殊段被计算后不再特殊,那么特殊段部分是 的。
对于非特殊段,只需记录最晚推平时间,那么问题相当于求 ,可以按填满时间进行二分但是多个 log,由于值域较小其实可以暴力预处理出每个 的答案。。
取 为 即可。
这题注意到被完全推平的段好做,而不完全推平的段可以暴力做,通过势能分析得到正确复杂度。
CF1129D Isolation(无代码,要补)
题意:求序列划分方案数,要求每一段恰好出现过一次的数的个数 。。
显然 dp,那么问题为移动右端点、快速查询合法左端点的 dp 值的总和。
数字相对独立,考虑一个数 ,它将序列划分为若干段,那么当右端点在一个区间时合法左端点也在一个对应区间,这样的区间是 个的。总共是 的。
将这些区间离线下来扫描线,问题变为:区间 ,求 位置的 dp 值的总和。询问难以用线段树维护。
尝试分块,记块长为 。
注意到对于整块的修改,若一开始对它进行排序并将相同的值相加起来,那只需用一个指针记录合法的前缀,修改只需左右移动指针。这启示我们维护整块有序。
考虑修改,对于散块,暴力重构排序并前缀和。由于本来整块有序,那么修改后得到几个有序序列,将它们归并即可,这样没有 log。对于整块做刚刚的操作即可。
考虑查询,对于整块,因为已经记录了指针可以直接得到答案。对于散块,暴力查询即可。
对于短区间,暴力即可。那么总复杂度是 。
这题是分块优化 dp,首先要想到数字贡献独立,将“恰好出现一次”转化为 个区间的限制。然后得到一个数据结构问题,需要想到维护整块有序方能解决。
P5443 [APIO2019] 桥梁(无代码,要补)
题意:在无向图上支持:修改边权、只走 的边求 连通块的大小。。可以离线。
显然 kruskal 重构树,假如无修改就很好做了,但是有修改只能暴力重构 kruskal 树。这时要想到套路:对时间序列(操作序列)分块。它的用处是减少重构次数。
分块后,一起处理一个整块的所有询问。对于该块内未修改的边,我们可以将边权排序后跑 kruskal,由于本题可以离线,将询问挂在 上便能得到每个询问对应的连通性。然后暴力补上被修改的边,最后使用回滚操作把这些边撤销即可。
取块长 ,。
本题是可撤销并查集与时间序列分块的结合。
P7722 [Ynoi2007] tmpq(无代码,要补)
题意:有数组 ,需支持:单点修改 、询问有多少个三元组 满足 。。
查询的形式实在是太怪了,不妨令 ,,那么问题变为单点改 ,查询 。
然后每个数字贡献独立,所以单独考虑。那么显然有 dp,记 考虑前 位且取了 个数字的方案。转移容易。
发现可以根号分治!对于出现次数(原序列次数加操作次数)小于 的,直接暴力计算 。然后考虑查询,相当于总共有 次单点改和 次前缀求和,根号一体两面一下 改、 查,总的就是 的。
对于出现次数 的只有 个,注意到 dp 可以用 ddp 的方式维护,注意这样就只能每种数字分别计算然后加起来了。转化为 次单点改、 次前缀积,依旧一体两面,总共 。具体来说,考虑修改对后面带来的影响即可。
令 则 。
本题需先转化三元组的形式,然后观察到数字独立并使用根号分治,同时分块带来的查询修改往往是 的,需要灵活运用一体两面以平衡复杂度。
CF1491H Yuezheng Ling and Dynamic Tree
题意:以 的形式给一棵树,支持 区间减(最多减到 )、求 。。
容易联想到弹飞绵羊,将序列分为 块,维护每个点第一次跳出整块到达的点。那么便能方便得求出 ,假如 不在同一块就让靠后的点跳出块;否则, 在块内当且仅当 跳出块到达的点相同,此时暴力跳即可。假如我们能 跳出块,就能 回答询问。
考虑怎么修改,对于散块暴力重构。注意到 只减不增,所以对于一个整块其操作次数 时一步就跳出,打个标记即可;否则就暴力重构。
总共 。
这题主要是联想到弹飞绵羊,然后观察到 不增的性质来优化修改。
树套树
很暴力这个东西。
考虑外层线段树的东西,单点改、区间查,单点查、区间改都是容易做的。注意外层线段树不能区间改,因为标记无法合并。
CF1080F Katya and Segments Sets
题意:给你 个集合,集合元素是区间。 次询问集合 是否均存在一个区间为 的子区间。。
套路:区间转二维数点。那么 包含 等价于 在 左上角。
考虑一个集合,那么合法的 构成一个上阶梯型,问题相当于判断 的阶梯的交是否包含 。
考虑怎么暴力做,将数点视为序列、其纵坐标为元素值,那么就是每个位置分别取 ,然后看看 是否 。
套路:若区间询问复杂,但前后缀询问容易,考虑猫树分治。本质上是将询问区间放在线段树上,则必然存在一个区间包含它且它跨过 ,也就是能拆为前后缀的形式。
本题可以分别判定前后缀。对于这个问题,每次新增一个集合时相当于做 次区间取 ,由于有序可以转为区间推平,势能分析可得复杂度正确。强制在线所以要用主席树。这个做法相当于线段树套主席树,时空间都是两个 log,非常劣。
事实上,只需求出每个集合 的最大 ,然后将每个集合最大 取 ,若其 就合法。那么直接按 从小到大加入,拿个主席树维护即可。。
不过转化和猫树套主席树的思路值得借鉴一下。
P3332 [ZJOI2013] K大数查询
题意: 个可重集,支持将区间内集合都加入 、查询区间内集合的并的第 大。。
集合的数 视为点 ,转化为二维数点。修改相当于一条线段都增加一个点,查询二分答案后相当于矩阵求和。树状数组套线段树即可。
P2086 [NOI2012] 魔幻棋盘
题意: 的网格,支持区间加、查询区间 ,保证查询区间包含定点 。。
由于 ,所以做一次差分后 不变,这样便解决了一维的问题。
对于二维的情况,考虑利用 ,将棋盘中心设为 ,分割为四个象限和四条轴分别求答案。每个象限 分别做一次差分,差分方向取决于到 方向。
那么变成了单点改、矩阵求 ,树套树!
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...