这么多天做了什么之写给自己看的数据结构题乱炖
洛谷 P5298 [PKUWC2018] Minimax
线段树合并好题。
首先
感觉妹啥好性质,于是对于每个结点维护其每个值的概率,向上合并。
对于只有一个儿子的结点很好维护,考虑怎么维护有两个儿子的结点:
将 \(x\) 结点处的值为 \(v\) 的概率记为 \(P(x, v)\)。
不妨设 \(v\) 在 \(x\) 的左儿子内,那么
考虑怎么把这个玩意丢到线段树合并上。
前后缀和可以直接在线段树合并的过程中搞掉,处理结点的过程中若两棵树该结点均非空则递归处理,若有一边非空,观察上面那个式子发现乘号右边的柿子对于整个结点都是相同的,直接打乘法 tag 即可,时间复杂度 \(\mathcal{O}(n\log n)\)。
洛谷 P2824 [HEOI2016/TJOI2016]排序
一句话题意:给出一个 \(n\) 个数的序列,每次选定一个区间将其升序/降序排序,求最终序列上第 \(k\) 位的值。
有一种二分 + 01 序列的双 \(\log\) 离线算法,这里是一种可以得到最终序列的在线算法:利用线段树分裂合并做到 \(\mathcal{O((n+m)\log n)}\)。
对于有序的连续段,我们只需记录其为升序/降序及其数集,数集用线段树维护,升降序打个 tag 就行。
每次操作使用线段树分裂合并,颜色段均摊分析可证明复杂度。
洛谷 P6018 [Ynoi2010] Fusion tree
一句话题意:给定一个 \(n\) 个结点的无根树,点有权值,\(m\) 次操作,分别为:
- 给某一点的所有相邻点权值 \(+1\);
- 单点修改;
- 查询与某一点的所有相邻点的权值异或和。
\(n,m \le 5\times 10^5\)
无根树不太好维护,一个常用的 trick 是将其转为有根树并将相邻点操作转为儿子统一维护,父亲单独处理。
对每个结点的所有儿子的权值建 01-Trie,发现整体 \(+1\) 不好维护,于是从低位往高位建 01-Trie,整体 \(+1\) 便相当于交换左右儿子并递归处理交换后需要进位的儿子,由于是单侧递归复杂度为 \(\log\) 级别。
单点修改是平凡的,异或和的维护只需在 01-Trie 上每个结点维护即可,时间复杂度 \(\mathcal{O}(n\log|S|)\)。
洛谷 P6665 [清华集训2016] Alice 和 Bob 又在玩游戏
一句话题意:给出一个 \(n\) 个结点的森林,双方轮流操作,每次选定一个结点并删除该节点及其全部祖先,不能操作的人败,问先手有无必胜策略。
\(n\le 10^5\)
SG 函数神题。
对每个结点开一个 01-Trie 存其子树对应的所有后继局面的 SG 函数值,再求出其子树对应的 SG 函数值,从下到上求解。
考虑对于一个点 \(p\) 的所有儿子求解完成后,如何求解该点对应子树所有后继局面的 01-Trie。
发现后继局面要么删 \(p\) 本身,要么删 \(p\) 的某个儿子对应子树上的点,删这个点本身对应的 SG 函数值就是其所有儿子的 SG 函数值异或和。
删去 \(p\) 某个儿子 \(sp\) 对应子树上的点,剩下的部分是在 \(sp\) 对应子树上删除这个点剩下的部分,和 \(p\) 的其他儿子对应子树,该后继局面所对应的 SG 函数值实际上就是在 \(sp\) 子树上删去这个点对应的 SG 函数值异或上结点 \(p\) 所有其他儿子对应的子树的 SG 函数值的异或和。
于是 \(p\) 所有后继局面的 01-Trie 就可以通过以下方法求出:
- 对于 \(p\) 每个儿子的 01-Trie 整体异或上 \(p\) 的其他儿子的 SG 函数异或和;
- 合并其所有儿子的 01-Trie;
- 插入其所有儿子的 SG 函数异或和。
而 \(p\) 的 SG 函数值只需要在其 01-Trie 上求 mex 即可,这需要记录 01-Trie 上每个点的大小。
最后将题目中给出的森林中每棵树的 SG 函数值异或起来就行啦,时间复杂度 \(\mathcal{O}(n\log|S|)\)。
UOJ #515. 【UR #19】前进四
一句话题意:维护一个长度为 \(n\) 的序列,\(m\) 次操作:单点修改,查询后缀严格最小值个数。
\(n, m\le 10^6\)
这题为了卡兔队线段树,略微卡常(?
离线询问,建立以时间为下标的线段树。对原序列从末尾倒序扫描,维护当前后缀最小值以及后缀最小值个数。
具体操作上,处理出每一位在每个时间段内的值,扫描原序列时在线段树上进行取 min 操作,记录每位变小的次数,经典 Seg-beats,时间复杂度 \(\mathcal{O}((n+m)\log n)\)。
洛谷 P6109 [Ynoi2009] rprmq1
一句话题意:给出一个 \(n\times n\) 的方阵,先进行 \(m\) 次子矩形加,再求 \(q\) 次子矩形 \(\max\)。
\(n, m\le 5\times 10^4, q\le 5\times 10^5\)
考虑扫描线,扫描二维方阵的其中一维。
子矩形加可以转化成先加后减,子矩形 \(\max\) 则是求一段时间区间内的区间最大值。
求某一段时间区间内的区间最大值可以使用历史最大值的 \(trick\) 套上一个线段树分治,本题中由于 \(m,q\) 规模不同,套上猫树分治时间更优。
时间复杂度 \(\mathcal{O(m\log^2n + q\log n)}\)。
孩子码力很差写不出来哭哭。
洛谷 P8527 [Ynoi2003] 樋口円香
一句话题意:给定一个长度为 \(n\) 的序列 \(\{a_i\}\),你有一个长度也为 \(n\) 的序列 $ {b_i}$,初始全为 \(0\),\(m\) 次操作,每次操作,给出 \(l,r,L\),需要对于\(k\in[l,r]\),将 \(b_{L+k-l}\) 增加 \(a_k\)。
\(n\le 10^5, m\le 10^6, \forall 1\le i\le n, a_i\le 1000\)
卷积题。
首先考虑将一个短序列多次整个加在一个初始全为 \(0\) 的长序列上,如果将短序列视为一个多项式,那长序列最终的值实际上就可以视为是短序列的多项式卷上了一个多项式,可以使用 FFT or NTT 优化。
回到本题,可以考虑将序列 \(a\) 分块,成块的用卷积优化,散块暴力。
时间复杂度玄学。
本题很卡常,建议写 FFT,反正窝 NTT 是根本卡不过去一点😰。
洛谷 P4688 [Ynoi2016] 掉进兔子洞
一句话题意:给出一个长度为 \(n\) 的序列,\(m\) 次询问,每次指定三个区间,问三个区间所对应的数集(可重集)的交集大小。
离线询问后莫队,使用 bitset 维护可重集,最后对于每个询问进行一个 bitset 按位与起来后的 popcount。
由于略卡空间所以要将询问分成 3 组回答。
有人做这道题时把莫队分块的比较函数写错了导致 RE 还不知道原因,真是笨蛋😆👉
P4887 【模板】莫队二次离线(第十四分块(前体))
原题部分题面:
珂朵莉给了你一个序列 \(a\),每次查询给一个区间 \([l,r]\),查询 \(l \leq i< j \leq r\),且 \(a_i \oplus a_j\) 的二进制表示下有 \(k\) 个 \(1\) 的二元组 \((i,j)\) 的个数。\(\oplus\) 是指按位异或。
\(1 \leq n, m \leq 10^5\),\(0 \leq a_i, k < 2^{14}\)
模板题。
莫队的每次移动要么增加一个数的贡献,要么减少一个数的贡献,假如这个贡献可以差分转化,那就可以把每次移动离线下来,扫描线处理贡献。对于维护扫描线的结构,插入是 \(n\) 次,询问是 \(\mathcal{O}((n + m)\sqrt{n})\) 次,需要注意平衡复杂度。
本题中离线询问后只需维护和某个数异或起来 popcount 为 \(k\) 的数的个数,时间复杂度为 \(\mathcal{O}(n\binom{14}{k} + (n+m)\sqrt{n})\)。
洛谷 P7906 [Ynoi2005] rpxleqxq
原题部分题面:
给你一个长度为 \(n\) 的正整数序列 \(a\),和一个常数 \(x\) 。
定义 \(x \oplus y\) 表示 \(x\) 异或 \(y\)。
有 \(q\) 次询问,每次询问给出一段区间 \([l, r]\),问你这个区间中有多少二元组 \((i, j)\) 满足 \(i < j \land (a_i \oplus a_j) \le x\)。
\(1 \le n, a_i, x\le 2\times 10^5, 1 \le q \le 10^6\)
同样是莫队二离,难点仅在于如何整一个数据结构来平衡复杂度。
考虑高低位分块,二进制下前 \(9\) 位分一块,后 \(9\) 位分一块,\(f_i\) 表示与前九位为 \(i\) 的数异或起来小于 \(x\) 的数的个数,\(g_{i, j}\) 表示前九位与 \(i\) 异或起来和 \(x\) 的前九位相同,后九位与 \(j\) 异或起来小于 \(x\) 的后九位的数的个数。
时间复杂度 \(O(2^9n + (n + q)\sqrt n)\)
洛谷 P6778 [Ynoi2009] rpdq
原题部分题面:
给定一棵 \(n\) 个节点的无根,有边权的树,每个点有个编号,编号为一个 \(1 \sim n\) 的排列。
共 \(m\) 组询问,每次询问给出 \(l,r\),求所有点编号的二元组 \((i,j)\) 满足 \(l \le i<j \le r\) 在树上的距离的和,两个点的距离定义为连接其的简单路径上的所有边的边权和。
还是莫队二离。
先将两点距离转化一下:
然后利用这道题的方法,将 \(dep_{lca}\) 的和转化成树上某一点到根的路径点权加和查询树上某一点到根的路径点权和。
需要用一种神奇的真·树分块平衡复杂度。
然后维护收缩树上的前缀和,每个簇内部的前缀和,即可做到 \(\mathcal{O}(\sqrt n)\) 插入,\(\mathcal{O}(1)\) 查询。
时间复杂度 \(O((n+m)\sqrt n)\)。