1.2 高级数据结构
\({\Large 约定}\):
- 用集合符号表示位运算符号,用 $ \oplus $ 表示异或,特别的,$ i \in S$ 表示二进制数 \(S\) 的第 \(i\) 位为 \(1\)
- 用 \(V\) 表示值域,\(\sum\) 表示字符集,\(\omega\) 表示
bitset的常数 \((\omega = 64)\)- 除去用 \(()/[]\) 表示开闭区间外,\([]\) 仅表示艾弗森约定,\(\{\}\) 仅表示集合,括号嵌套全用 \(()\)
- 字符串或序列角标为区间表示对应区间的子串
\(\textcolor{white}{\mathrm{pw:hELlOwoRlD}}\)
P3835 【模板】可持久化平衡树
\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 平衡树 可持久化
我只会 FHQ-Treap 所以只能写可持久化 FHQ-Treap 了QAQ。
发现这个与可持久化线段树的想法比较类似,只需要把在修改路径上的点都复制出来。
每次操作时都找到对应版本的根,然后再从这个根开始往下分裂/合并。每到一个位置就新建一个结点,其他与普通平衡树差别不大。
2025.12.18
P5055 【模板】可持久化文艺平衡树
\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 平衡树 可持久化
可持久化文艺平衡树与可持久化平衡树一样,都需要在 \(split、merge\) 以及 \(push\_down\) (划重点)的时候复制一份新的结点。
其他的话只需要在不用可持久化的板子上略作修改即可。
一些实现上的小细节:
这里如果在 \(sz_{ls}+1=k\) 的时候直接退出会有一点问题,所以需要在 \(sz_{ls}+1\leq k\) 的时候继续遍历左子树。
2025.12.18
P5586 [P5350] 序列 (加强版)
\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 平衡树 可持久化
感觉略微有一点点毒瘤?虽然思路还是比较明确的就是了。
如果没有 将区间 \([l_1,r_1]\) 与 \([l_2,r_2]\) 交换 这个操作的话,其实是很好维护的,只需要维护一些 tag 以及平衡树的分裂即可,要注意一些操作的顺序。
如果加上这个操作的话每次复制一遍这个树显然是不太现实的。那我们用类似可持久化平衡树的想法,在进行 \(split/merge/push\_down\) 操作的时候复制一遍修改的结点,相当于建了一个新的树。只需要把这个新的树加入合并中就可以实现复制的操作。
当然这道题也是卡空间的,所以在空间差不多的时候要重构一下。先求出树的中序遍历,再 \(\mathcal{O(n)}\) 建树即可。
细节有亿点点多。要注意该开 \(longlong\) 的时候还是要开的,不然容易 RE。
2025.12.19
P3380 【模板】树套树
\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 线段树 树状数组 分块
其他树套树我都不会啊,我只会树状数组套可持久化权值线段树啊QAQ
如果说这道题没有修改的话其实与可持久化线段树 2还是很像的。我们像平衡树那样创造两个基本运算:查询 \(k\) 在区间内的排名、查询区间内排名为 \(k\) 的值。前者只需要求有多少个数比 \(k\) 小,后者也只需要判断子树大小有没有大于 \(k\) 然后往下递归就行了。
前驱和后继也可以通过这两个运算去求。求前驱时,先查询 \(k\) 在区间内的排名 \(p\),然后求区间内排名为 \(p-1\) 的数即可。
同样,求后继时,先查询 \(k+1\) 在区间内的排名 \(p\),然后求区间内排名为 \(p\) 的数即可。
当然有些不存在的情况需要特判一下。
待修改了要怎么做呢?我们想到树状数组修改和查询都是 \(\mathcal{O(\log n)}\) 的,也可以把这种思想运用进来。
每次修改某一个位置上的数值的时候,把这个位置对应树状数组上的修改位置的权值线段树全部修改一下,这样复杂度是 \(\mathcal{O(\log^2 n)}\) 的。查询也是同样道理。
2025.12.21

浙公网安备 33010602011771号