【笔记】数据结构选讲 2024.7.31 & 2025.7.31
【笔记】数据结构选讲 2024.7.31 & 2025.7.31
- 【笔记】数据结构选讲 2024.7.31 & 2025.7.31
- 【模板】"动态 DP"&动态树分治(树剖)
- [Ynoi Easy Round 2020] TEST_63(LCT)
- [JOISC 2019 Day2] Two Antennas(历史最值)
- [Ynoi2002 / CTT2022] Optimal Ordered Problem Solver(修改分类)
- [CTT2021] 简单数据结构(修改分类)
- [Hangzhou23F] Top Cluster(直径性质)
- [dmopc21c8p6] Castle Building(匹配)
- [NOIWC2024] 线段树(树上 dp)
- [Ynoi2009] rprmq1(历史最值)
- [Hangzhou23K] Card Game(可持久化平衡树)
- [Hefei23K] Campus Partition(树上 dp)
- [KOI TST 2023] 택시 여행 / Taxi(点分)
- [CTT2021] 小明的树(点边容斥)
- [2022-2023 集训队互测 Round 2] 相等树链(点分、hash)
- [CF1707E] Replace(倍增)
- [CF1558F] Strange Sort(0/1 转化)
- [QOJ4815] Flower's Land(点分、树上背包)
- Segbeats(势能分析)
- ABC414G AtCoder Express 4(线段树优化建图)
- qoj9694 Light Drinking and Low Singing(平衡树)
- qoj9419 Normal Friends(LCT)
- Gym-105667C MIT Tour(树剖线段树)
- qoj2064 Bitset Master(点分治)
- 无标题(树剖、树上背包)
- [WC2018] 通道(边分治、虚树、直径)
- qoj6350 MIT(一般图的匹配、重心)
- 无标题(边分治、Boruvka)
同一个人讲的同一个专题,合并了。
【模板】"动态 DP"&动态树分治(树剖)
P4719 【模板】"动态 DP"&动态树分治 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这样可以轻易写为树剖,令 \(v=son(u)\)。
[Ynoi Easy Round 2020] TEST_63(LCT)
P8265 [Ynoi Easy Round 2020] TEST_63 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
用 LCT 维护重链剖分,LCT 上的虚实边直接代表重链剖分上的轻重边。
维护一条链的信息(修改一条链的轻重边情况):先 access 链底全改成重边,再考虑维护树链剖分(显然根据定义只会改轻 \(O(\log n)\) 条轻边)。枚举 \(k\),在平衡树上二分找到这个 \(u\),然后去检查 \(u, v\) 是不是应该变轻。
在 LCT 上维护轻子树信息是能做的。然后你维护了重链信息之后就能做了。
维护一个集合,支持增删 \(\max\),可以开两个 priority_queue,一个存下加的数,一个存下删的数。
[JOISC 2019 Day2] Two Antennas(历史最值)
#3033. 「JOISC 2019 Day2」两个天线 - 题目 - LibreOJ (loj.ac)
扫描线,试图维护历史最大值信息。对于天线 \(i\),相当于它有一个注册时间和注销时间。对于天线 \(j\),扫到它的时候会有一个合法的 \(i\) 区间可用。维护两个序列 \(a, b\),初始都是 \(-10^9\);\(i\) 注册时,将 \(a_i\) 修改为 \(-h_i\);\(j\) 扫到时,将 \(b[]\) 区间复制为 \(h_j\),然后再推平回去。维护区间 \(a_i+b_i\) 的历史最大值的最大值。绝对值符号反过来的,reverse 再做一次。
[Ynoi2002 / CTT2022] Optimal Ordered Problem Solver(修改分类)
P9061 [Ynoi2002] Optimal Ordered Problem Solver - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
所有的点,要么没有被操作过,要么在操作矩形的并的轮廓线上。
修改:轮廓线上的点做 \(x_i\) / \(y_i\) 的区间复制,外面的点暴力查找加入。
查询:轮廓线上的点截取出来数一下,外面的三维偏序。
三维偏序是 \(O(n\log^2n)\) 的,优化是容斥,拆成上方(二维)、右方(二维)、右上角(都没被修改过,可以直接做)。
[CTT2021] 简单数据结构(修改分类)
【北大集训2021】简单数据结构 - 题目 - Universal Online Judge (uoj.ac)
如果没有 3 操作而是最后输出序列,那么可以将一堆操作合并为 \(a_i\gets \min_j(a_i+ki, v_j+t_ji)\)。后者是上凸壳,说明被修改的点是始终单调递增的。
如果已经知道每个点的首次修改时间,则可以使用线段树标记维护。为了求出前者,使用整体二分。每次整体二分求一个凸壳出来,看一眼怎么修改,然后分下去。
[Hangzhou23F] Top Cluster(直径性质)
Top Cluster - Problem - QOJ.ac
权值互不相同是关键。二分答案,查询 \(1\sim v\) 的点是否与询问点距离 \(\leq d\),取到最值的点一定是一条直径的一端。
[dmopc21c8p6] Castle Building(匹配)
[DMOPC '21 Contest 8 P6 - Castle Building - DMOJ: Modern Online Judge](https://dmoj.ca/problem/dmopc21c8p6#:~:text=Initially, 1 3 4 5 7)
分讨 \(n\) 出现的位置,改写成未出现的数匹配区间的形式,尝试使用 Hall 定理,需要对所有 \(l\leq r\) 判定一个二维的东西 \(\sum a\leq\sum b\)。全体区间可以写成两行,每一行的区间互不相交。所以我们首先对每个区间都判一次 Hall 定理。然后,考虑对于一个区间 \([L,R]\),原来是对 \([l, r]\ni[L,R]\) 有容量的贡献,考虑对 \([l, r]\in[L,R]\) 的减去这个区间的容量,这样不影响判定。于是可以转成一维的东西。修改只影响 \(O(1)\) 个区间。
[NOIWC2024] 线段树(树上 dp)
P10145 [WC2024] 线段树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
会了,不想写题解啊
[Ynoi2009] rprmq1(历史最值)
P6109 [Ynoi2009] rprmq1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
将询问拆成二区间合并的形式。以拆出的右区间为例,为了保证所有矩形加操作都有顾及,可以考虑在同一层中处理这些区间。用一棵历史最大值线段树扫过去,扫到一个分治区间中点的时候,为了保证查询不被中点前面部分影响,可以给全局加一个 \(+\infty\),放弃之前已经消失的最值(但是现在还在的矩形还留着),询问的时候再抠掉 \(+\infty\)。注意 \(+\infty\) 的选取。\(O(m\log^2n+q\log n)\)。
[Hangzhou23K] Card Game(可持久化平衡树)
记 \(t_i\) 为下一个与 \(a_i\) 相同的数的下标,那么:
\(l\) 从右往左扫,可持久化平衡树解决区间复制问题。
[Hefei23K] Campus Partition(树上 dp)
Campus Partition - Problem - QOJ.ac
所划分的一定是链,且链的两端是最大值与次大值(否则不优)。\(f_u\) 表示 \(u\) 子树内匹配完成的最大值,\(d_{u,x}\) 表示 \(u\) 子树内的点 \(x\) 要飞出去匹配。\(d_{u,x}\) 转移即为 \(=\max_{v}\{d_{v,x}+\sum_{v'\neq v}f_v\}\)。\(f_u\) 转移即枚举 \(v_1, v_2\) 并取 \(d_{v_1,x}+d_{v_2,y}+\min(a_x, a_y)\) 以及其他的 \(f_{v'}\) 的和。
可以线段树合并维护 \(d_{u,x}\)。合并的时候除了维护出 \(d_{u,x}\) 以外,还要求 \(f_u\)。递归到只有一边有值的时候就可以转移 \(f_u\),向下递归时记录左右儿子的某个值的最值即可,反正线段树合并可以做。
[KOI TST 2023] 택시 여행 / Taxi(点分)
运行 Dijkstra 算法。
点分树,需要支持在所有点分树父亲上插入一次函数,查询单点最小值,写若干李超线段树即可。都是平凡的。
[CTT2021] 小明的树(点边容斥)
【北大集训2021】小明的树 - 题目 - Universal Online Judge (uoj.ac)
点边容斥计算连通块,只需要分开讨论每一条边什么时候给谁有贡献,需要求 \(\sum[\text{未点亮的点-边}=1]\sum[\text{点亮的点-边}]\),写成 \(\sum[a=1]\sum b\) 算了,显然 \(a=1\) 已经是最小值,所以写为 \(\sum [a=\min a]\sum b\),线段树随机维护一下就好了。修改操作甚至不需要维护树形态,而只是 \(O(1)\) 个区间加。
[2022-2023 集训队互测 Round 2] 相等树链(点分、hash)
点分治到重心 \(rt\)。考虑采取异或哈希判定相等,随机权值 \(c_i\)。从 \(rt\) 出发的路径,我们要选两条拼起来,观察到这两条路径拼起来在 \(T_2\) 上的路径两端点 \(\in\) 由这两条路径各自在 \(T_2\) 上组成的路径两端点(一共四个点)的集合。枚举在 \(T_2\) 上的路径两端点分别来自哪里,使用极其恶心的树上前缀异或和的 LCA 分讨随机完成。
[CF1707E] Replace(倍增)
Replace - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
重要的观察:
这样就好多了啊!
倍增:
任意 RMQ 算法,没了啊!
[CF1558F] Strange Sort(0/1 转化)
Strange Sort - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
枚举 \(v=1\sim n\),将 \(\leq v\) 的标记为 \(0\),\(>v\) 的标记为 \(1\),并尝试将其排序成 \(v\) 个 \(0\) 和 \(n-v\) 个 \(1\),对所有时间取最大值作为答案。考虑所有 \(1\) 的位置,从右往左记为 \(x_1, x_2, \cdots, x_k\),那么 \(x_1\) 被移到正确位置的时间为
\(+0/1\) 是因为有个奇偶修正的部分。
\(t_2\) 和 \(t_1\) 一样,不过 \(x_2\) 可能会被 \(x_1\) 挡住,但如果是这样,则 \(x_2\) 一定会紧随 \(x_1\) 之后到达它的位置。
我们要求的是
外层的 \(v\) 减少时,这些 \(t\) 是区间修改,或者平衡树都可以做。
[QOJ4815] Flower's Land(点分、树上背包)
题解 QOJ4815【Flower's Land】 - caijianhong - 博客园 (cnblogs.com)
Segbeats(势能分析)
线段树支持 1. 区间 chkmin \(v\);2. 区间和。
考虑在线段树上每个节点维护 \(max1, max2, num, sum\) 表示最大值,严格次大值,最大值出现次数,区间和。chkmin \(v\) 的操作,分类讨论:
- \(v\geq max1\):无影响。
- \(max1>v>max2\):打上标记,表示以后将所有最大值改为 \(v\),不往下递归,\(sum\) 可以维护。
- \(max2\geq v\):暴力向下递归。
复杂度分析:暴力向下递归之后,这个线段树区间的不同值的个数会至少减少一,总不超过 \(O(n\log n)\)。
如果加上区间加操作,复杂度变为 \(O(n\log^2n)\) 但是实际表现和 \(O(n\log n)\) 差不多,但是没人会证。听说这东西常数不小。
ABC414G AtCoder Express 4(线段树优化建图)
线段树优化建图,但是因为 Dijkstra 要求不能有负权边,所以改造线段树上的边的边权。例如从左往右的列车,左区间对应的线段树中,从下往上走时,认为是往数轴上的右边走,区间 \([l,r]\) 表示当前在 \(x_r\) 的位置,向上走的时候边权设为走到对应位置的边权;右区间对应的线段树中,从上往下走时,认为是往数轴上的左边走,区间 \([l,r]\) 表示当前在 \(x_l\) 的位置,向下走的时候边权设为走到对应位置的边权。然后线段树优化建图即可。
qoj9694 Light Drinking and Low Singing(平衡树)
01 变成 10 相当于所有 0 右移且所有 1 左移,特殊情况是边界情况和 000011111 会相撞成 0001111(长度 \(>1\) 的连续段相撞后长度各自 \(-1\))的情况。那么观察长度 \(>1\) 的连续段的长度和,每次相撞 \(-2\),边界上会 \(+O(1)\),也就是说总相撞次数为 \(O(n)\),暴力维护相撞即可。平衡树维护。
qoj9419 Normal Friends(LCT)
LCT 维护树形态。一条重链上维护:
- 0/1 序列表示重链上 \(i+1\) 号点是 \(i\) 号点的左 / 右儿子。
- 所有 0 的标号序列,以及它的翻转 tag。
- 所有 1 的标号序列,以及它的翻转 tag。
Access 操作时:需要对这三个序列进行 split / merge 操作,故使用无旋 Treap 维护序列。
Tag 的下放:tag 表示将整棵子树的左右儿子翻转,需要 flip 第一个序列,swap 第二、三个序列,并对第二、三个序列继续打 tag(Tag 很可能要放到无旋 Treap 上进行维护)。
询问就 access 并打 tag 就行了。
Gym-105667C MIT Tour(树剖线段树)
标准题。按深度进行 dp。可以点分治。可以树剖线段树,意思就是,假如上一层是 \(v\),下一层是 \(u\),则考虑它们的 LCA,\(u\) 去枚举 LCA 在它头上的哪条重链上,然后分类讨论,看看 \(v\) 跳到这条重链上时,是在 \(u\) 下方还是 \(u\) 上方,由此得到两种转移。然后用线段树优化一下就可以了。
qoj2064 Bitset Master(点分治)
难绷:【20省选集训day1】Bitset Master | Zhengrui Online Judge。
点分治。先求出 \(u\) 第一次走到根的时刻,这个可以以边为对象进行 dp。再求出 \(u\) 走到其它子树的时刻,也就是多次询问(离线)第 \(i\) 时刻从根出发走到别的子树去,在 \(q\) 时刻之前能走到多少个点。可以从小到大枚举 \(i\),每次增大时,暴力向下 dfs 去更新每条边经过的时刻。
无标题(树剖、树上背包)
dfs 时做背包。\(dp_{u,sa,S}\) 表示当前在 \(u\) 点,\(\sum a_i=sa\),\(u\) 到根路径上每个点选或不选的状态记为 \(S\)。然后像上文 Flower's Land 一题的方法进行背包。优势是复杂度中 \(k\) 的指数仅为 \(1\)。
为了击杀 \(2^n\),我们树剖,先遍历轻儿子再递归重儿子,并规定:仅在我们可以确定一个点的选或不选状态时,将它从 \(S\) 中击杀。这样 \(S\) 中只会剩下 \(O(\log n)\) 个点,也就是到根路径的所有轻儿子父亲(为什么???)。复杂度 \(O(n^3k)\)。
[WC2018] 通道(边分治、虚树、直径)
【笔记】树论选讲 2023.12.14 - caijianhong - 博客园
qoj6350 MIT(一般图的匹配、重心)
结论:匹配点集是单调的。可以用费用流考虑二分图的情况。
当 \(k=n/2\) 时,匹配点集是所有点。匹配的具体方案可以选出树的重心,这样所有点都能通过重心两两匹配了。答案就是所有点到重心的距离的和。
当 \(k\) 减少时,我们删除离当前重心最近的点,并移动重心。将重心移动到最大的子树(如果它的大小 \(>siz_{rt}/2\))。如何判断当前重心是否合法呢?先判断它头上的子树合不合法,再判断它子树中的中位点所在子树是否合法,即可。
无标题(边分治、Boruvka)
有一棵树,边带整数权。求一个完全图的最小生成树,\(u,v\) 的边权为 \(|dist(u,v)|\)。
边分治,每层内求出只考虑 \(u\in S, v\in T\) 的边的最小生成树,并保留它们,最后剩下 \(O(n\log n)\) 条边,求最小生成树。
边分治一层里面,我们可以用 Boruvka 算法,用双指针求出最近的点。
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18332787
浙公网安备 33010602011771号