数据结构选讲
课件知识点不太了解的
-
莫队二次离线。
-
操作树,可撤销并查集+分块。
-
惰性堆。
-
树分块。
trick 整合
-
对于这种公约数题目,我们都可以拆成与枚举质数有关的东西,这是比较典的拆贡献方法。
-
根号分治对于质数的运用。
-
莫队左右端点移动时先考虑扩张,在考虑缩小。
-
对于排序问题,很多时候我们都可以转成 01 来考虑,研究排序的本质就是把 0 前移,1 后移。
题目
P2824 [HEOI2016/TJOI2016] 排序 \(\checkmark\)
题目大意
给定一个 \(1\sim n\) 的排列,进行 \(m\) 次操作:
0 l r:将下标区间 \([l,r]\) 内的数升序排序;1 l r:将下标区间 \([l,r]\) 内的数降序排序。
所有操作结束后,询问第 \(q\) 个位置上的数字。\(n,m\le 10^5\),\(1\le q\le n\)。
解题思路
我们只需要查询一个位置,这很好。
对于排序问题我们都可以考虑转 01,二分 mid,做一遍 \(m\) 次操作,只需要用线段树模拟,支持区间修改成 0 或者 1,区间查询 1 的个数,最后看看第 \(q\) 位是不是 0/1,继续二分。时间复杂度 \(O(m\log n)\)。
启发:
- 对于排序问题,很多时候我们都可以转成 01 来考虑,研究排序的本质就是把 0 前移,1 后移。
P6619 [省选联考 2020 A/B 卷] 冰火战士 \(\checkmark\)
题目大意
有冰、火两派战士,每个战士有温度 \(x\) 和能量 \(y\)。给定场地温度 \(T\) 时:
- 冰系战士可参赛当且仅当 \(T\ge x\);
- 火系战士可参赛当且仅当 \(T\le x\)。
双方可参赛战士按题述顺序依次对战,双方每轮消耗相同能量。若冰系可参赛总能量为 \(I(T)\),火系可参赛总能量为 \(F(T)\),则总消耗为
求使总消耗最大的最高温度 \(T\),并输出该温度及最大总消耗;若不存在使双方都有战士可参赛的温度,输出 Peace。
动态维护:共 \(Q\) 次操作,每次加入一个战士(给出派系 \(t\)、温度 \(x\)、能量 \(y\))或撤回之前某条加入操作,要求在每次操作后立即输出当前答案。
\(1\le Q\le 2\times 10^6\),\(1\le x\le 2\times 10^9\),所有 \(y\) 之和不超过 \(2\times 10^9\)。
解题思路
简单转化后的题意如上,肯定可以离散化。仔细读一读,相当于我们需要动维护一个单调的离散函数,\(f\) 单调不降,另外 \(g\) 单调不增,我们需要求出一个离散位置使得两个函数值的 \(min\) 最大,在 \(min\) 最大情况下位置下标也最大。
其实本质是求两条函数 \(f,g\) 的交点,但是这是离散的。所以我们就变成了求最大的 \(f(x)\le g(x)\) 的 \(x\),以及最前的 \(f(x)>g(x)\)(这个前一个 \(x+1\) 即可),注意,这里如果存在 \(x'>x\) 且 \(g(x')=g(x)\),那么取 \(x'\)。
动态来做的话就需要上数据结构,一方面支持后缀前缀修改,一方面也要支持二分(如果要单 \(\log\)),我们肯定可以用线段树来做,但是如果你想要更优常数(这道题卡)也可以用树状数组,难点在于树状数组上的倍增。
实现上前后缀修改其实可以统一,其中一个最后用总结果减一减算一算就行了。
启发:
- 当成树状数组练手题。
CF1762F Good Pairs \(\checkmark\)
题目大意
给定长度为 \(n\) 的数组 \(a\) 和整数 \(k\)。若存在下标序列 \(i_1,i_2,\dots,i_m\),满足:
- \(i_1=l\),\(i_m=r\);
- \(i_1<i_2<\cdots<i_m\);
- 对每个 \(1\le j<m\),都有 \(\lvert a_{i_j}-a_{i_{j+1}}\rvert\le k\),
则称点对 \((l,r)\) 是“好对”。求满足 \(1\le l\le r\le n\) 的“好对”数量。
多组数据,\(1\le t\le 10^5\),\(1\le n\le 5\cdot10^5\),\(0\le k\le 10^5\),\(1\le a_i\le 10^5\),且所有数据中 \(n\) 之和不超过 \(5\cdot10^5\)。
解题思路
首先考虑判定一个区间 \([l,r]\) 是不是好的,我们发现,对于好的序列,它一定是单调的,因为如果存在 \(x\to y\to z\) 且满足 \(a_x>a_y<a_z\) 或者 \(a_x<a_y>a_z\),那么 \(x\to z\) 也是合法的,所以一段合法序列肯定等价于一个单调的序列。
注意也有可能是 \(a_x=a_y\),它们也能到,所以这个可以提前算出,最后容斥掉。
单调不增和单调不降是对称的,所以我们这里统一考虑单调不降。
我们倒着处理,对于 \(i\),找到最小的 \(j\) 满足 \(a_j\in (a_i,a_i+k]\),定义其为 \(nxt_i\),容易发现定义 \(f_i\) 为以 \(i\) 为左端点的好区间个数,那么在这里 \(f_i\gets f_{nxt_i}\),但是还有一些位于 \((a_i,a_{nxt_i})\) 之间的数是 \(i\) 到的了的,\(nxt_i\) 到不了的。
综上所述,我们需要找到 \(nxt_i\),统计 \([a_i,a_{nxt_i}]\) 的数的个数,所以用一颗权值线段树足够了,并且值域数据范围是小于 \(n\) 的,所以能过。
统计单调上升的就是把序列翻转一下就行了。
P9060 [Ynoi2002] Goedel Machine \(\checkmark\)
题目大意
给定长度为 \(n\) 的序列 \(a_1,\dots,a_n\)。有 \(m\) 次询问,每次给出区间 \([l_i,r_i]\),求
即该区间内所有非空子集的最大公约数之积,对 \(998244353\) 取模。
\(1\le n,m,a_i\le 10^5\),\(1\le l_i\le r_i\le n\)。
解题思路
对于这种公约数题目,我们都可以拆成与枚举质数有关的东西,这是比较典的拆贡献方法。
比如说,经典的,我们枚举每个质数 \(p\),数一数当前询问区间有多少个数是满足 \(p\mid a_i\),假设当前个数为 \(c\),那么这个质数的贡献是 \(p^{2^c-1}\)。进一步,我们发现其实可以枚举 \(p^k\),每次就相当于在 \(p^{k-1}\) 的基础上增量而已。
分析复杂度,我们的质数幂次个数是大于质数个数的,但是比较接近,可以自己写份代码验证一下。因为质数个数是 \(O({n\over \ln n})\) 级别的,所以这样做的复杂度肯定会炸掉。
我们尝试套上经典 trick,根号分治,记 \(w=\max a_i\),将 \(p\) 分成 \(\le \sqrt w\) 和 \(>\sqrt w\) 的。
对于 \(p\le \sqrt w\),我们直接用上面的思路,预处理出 2 的幂次还有逆元,这样的复杂度是不会超过 \(O(m\sqrt w+m\sqrt w)\)。
对于 \(p>\sqrt w\),每个 \(a_i\) 至多只有一个这样的 \(p\),所以我们可以用莫队,每次移动左右端点都只会使区间内的 \(p\) +1,-1,所以这一部分也用上预处理之后的时间复杂度是 \(O(n\sqrt m)\)。
预处理最好不是 \(2^k\) 此方的,这个后面还是比较麻烦,可以直接预处理 \(p^{2^k}\),最后在 \(\times p^{-1}\) 即可。
\(n,m,w\) 同阶,总时间复杂度就是 \(O(n\sqrt n)\)。
启发:
-
对于这种公约数题目,我们都可以拆成与枚举质数有关的东西,这是比较典的拆贡献方法。
-
根号分治对于质数的运用。
-
莫队左右端点移动时先考虑扩张,在考虑缩小。

浙公网安备 33010602011771号