一些前几天做过的还不错的但是不是太想专门花一整篇博客的篇幅去写的题就简要地记录在这里。
说是简要题解,其实写得还是挺详细的。之后的杂题记录可能就会写得简略一点。
CF1060E Sergey and Subway
显然若原图中两点间的距离为 \(\rm dis\),那么新图中的距离就为 \(\left\lceil \frac{{\rm dis}}{2} \right\rceil\)。因此答案为 \(\sum_\limits{i = 1}^{n} \sum_\limits{j = 1}^i \left\lceil \frac{{\rm dis}(i, j)}{2} \right\rceil\)(\({\rm dis}(i, j)\) 表示原图中 \(i, j\) 两点间的距离),其中的上取整很不好处理,不过注意到我们只要再为每一个 \(\rm dis\) 为奇数的点对的分子加上 \(1\),就可以直接用分子和除以 \(2\) 得到答案了,换句话说,答案等于 \(\frac{\sum_\limits{i = 1}^n\sum_\limits{j = 1}^i {\rm dis}(i, j) + [{\rm dis}(i, j)是奇数]}{2}\)。因此我们可以先 dfs 一遍得出任意点对间的距离和,再统计距离为奇数的点对的数目即可。
记录每个点 \(i\) 到根节点的距离 \(d(i)\),那么若 \(i, j\) 两点间的距离为奇数,一定满足 \(d(i), d(j)\) 一个为奇一个为偶,因此用 \(d(i)\) 为奇数的点 \(i\) 的数量乘以 \(d(i)\) 为偶数的点 \(i\) 的数量就得到了距离为奇数的点对的数目。
luogu4948 数列求和
令 \(S_k = 1^ka^1 + 2^ka^2 + 3^ka^3 + \cdots + n^ka^n\),那么 \(aS_k = 1^ka^2 + 2^ka^3 + 3^ka^4 + \cdots + n^ka^{n + 1}\)。
所以 \((a - 1)S_k = n^ka^{n + 1} - a +\sum_\limits{i = 2}^n\left((i - 1)^k - i^k\right)a^i\)
因为 \((i - 1)^k = \sum_\limits{x = 0}^{k} \binom{k}{x} (-1)^{k - x} i^x\)
故:\[\begin{aligned}\sum_{i = 2}^n\left((i - 1)^k - i^k\right)a^i &= \sum_{i = 2}^n a^i \left(\sum_{x = 0}^{k - 1} \binom{k}{x} (-1)^{k - x} i^x\right) \\ &= \sum_{x = 0}^{k - 1} \binom{k}{x} (-1)^{k - x} \left(\sum_{i = 2}^n a^ii^x \right) \\ &= \sum_{x = 0}^{k - 1} \binom{k}{x} (-1)^{k - x} (S_x - a)\end{aligned}\]
因此有 \[S_k = \frac{n^ka^{n + 1} - a + \sum_{x = 0}^{k - 1} \binom{k}{x} (-1)^{k - x} (S_x - a)}{a - 1}\]
这样就可以 \(O(k^2)\) 递推了。不过注意到当 \(a = 1\) 时按照上式算会出问题。当 \(a = 1\) 时本质上就是求自然数的 \(k\) 次幂的和,因此直接上拉格朗日差值即可。
BZOJ1974 [SDOI2010]代码拍卖会
首先,一个合法的数一定可以写成不超过 \(9\) 个形如 \(\frac{10^k - 1}{9}\) 的数的和(例如:\(1123356678 = 1111111111 + 11111111 + 1111111 + 11111 + 11111 + 1111 + 11 + 1\))。
有了这一步,这个题就好做了。由于 \(\frac{10^k - 1}{9}\) 当 \(k\) 不断增大时,其模 \(p\) 的值会出现周期,因此我们可以很快地求出模 \(p\) 意义下每个值对应了多少个不同的数。这之后,我们就可以 dp 了。我们将所有数按模 \(p\) 的值分组,设 \(f_{i, j, k}\) 表示考虑了前 \(i\) 组,已经选出了 \(j\) 个数,且当前已选出的数模 \(p\) 的值为 \(k\) 的方案数。转移枚举当前这一组选了多少个数,方案数可用插板法计算。
由于合法的数的最高位必须是 \(1\),因此必须要选择至少一个 \(\frac{10^n - 1}{9}\),最后特殊处理一下即可。
luogu4942 小凯的数字
\([l, r]\) 内每一个数 \(w\) 对最终拼成的数字的贡献都可以写成 \(w \times 10^k\) 的形式。由于 \(w \times 10^k\ {\rm mod}\ 9 = w\ {\rm mod}\ 9 \times (10\ {\rm mod}\ 9)^k = w\ {\rm mod}\ 9\),故直接统计 \([l, r]\) 内所有数字和即可。
BZOJ4939 [Ynoi2016]掉进兔子洞
直接将原序列排序(不去重),这样我们就能用 bitset 表示一个区间一共有多少个数(而不是多少种数)出现过了。离线询问后用莫队即可,那么一次询问都出现的数就是询问对应的三个区间的 bitset 的并。
不过我们不能同时处理所有的询问,因为我们无法开下 \(10^5\) 个长度为 \(10^5\) 的 bitset。但注意到本题的时限较大,因此可以用时间换取空间,将询问分成 \(4\) 批处理即可。
LOJ2568 [APIO2016]烟花表演
首先,任意一棵子树内将所有点到子树的根的距离设为 \(x\) 的代价 \(f(x)\) 是下凸的。考虑将函数 \(f(x)\) 从叶子结点向上合并。
第一种情况:由子结点合并至父结点。此时分类讨论。设子节点函数值取到最小值的区间为 \([l, r]\),合并后函数为 \(f'(x)\),子结点到父结点边的边权为 \(w\),那么有:
\[f'(x) = \begin{cases}f'(x)=f(x)+w, &x < l \\ f'(x) = f(l) + w - (x - l), &l \leq x < l + w \\ f'(x) = f(l), &l + w \leq x < r + w \\ f'(x) = f(r) + x - r - w, &x \geq r + w\end{cases}\]
注意到对于任意 \(f(x)\),除了取到最低值时,函数任意一段的斜率 \(k\) 均有 \(|k| \geq 1\),因此对于新函数 \(f'(x)\),\([l, l + w]\) 与 \([r + w, \infty]\) 内的值均会表示成经过点 \(f(l)\) 或 \(f(r)\) 的一次函数,这样一定是最优的。
第二种情况:多个子结点合并。凸包直接相加即可。
注意到我们只需要记录从左至右斜率发生变化(即斜率 \(-1\))的点的 \(x\) 坐标即可。因为对于一个结点 \(u\),若以 \(u\) 为根的子树内有 \(k\) 个叶子结点,那么其对应 \(f(x)\) 的凸包的最左边的斜率即为 \(-k\)。如果我们得到了最终 \(1\) 号结点的函数凸包对应的所有拐点坐标,那么我们只需根据 \(f(0)\) 与初始斜率递推即可得到答案,而 \(f(0)\) 即为所有边的边权和,这样,问题就迎刃而解了。
按照这样维护,第一种情况就变为了删掉斜率为正的直线对应的拐点,同时插入斜率为 \(-1, 0, 1\) 的直线对应的拐点,第二种情况就变为了将所有点合并起来。那么我们需要一个能维护所有点的 \(x\) 坐标值,支持弹出最大值与插入,支持合并的数据结构。用左偏树即可。
LOJ6468 魔法
按种类离线,那么可以将一次询问差分,对于一次询问,处理到种类 \(l - 1\) 时减去区间的总贡献,处理到种类 \(r\) 时加上区间的总贡献即可。
如何计算新增一个种类的水晶后对所有点的贡献?假设相邻的两个水晶的位置分别为 \(t_1, t_2\),那么令 \({\rm mid} = \frac{t_1 + t_2}{2}\),分左右讨论。由于一个水晶 \(i\) 对一次询问的贡献为 \(|p - t_i|\),把它拆开,对于一次询问,\(p\) 是固定的,我们可以最后再算,那么只需要对所有对应的询问加上或减去 \(t_i\) 即可,可以直接线段树区间修改。
CF1038E Maximum Matching
将两端的数字看成点,一个色块看成边,那么原题转化为需要在一幅包含 \(4\) 个结点的图中找一条边权和最大的欧拉路。
首先,存在欧拉路的充要条件是所有点中度数为奇的点要么有 \(0\) 个要么有 \(2\) 个。我们单独考虑一个连通块。若一个连通块内有 \(4\) 个点,\(4\) 个点的度数只可能出现:奇奇奇奇、偶偶奇奇、偶偶偶偶这三种情况。显然对于第二种或第三种情况,可以找到一条欧拉路包含所有边,对于第一种情况,只需删掉一条边,也可以找到一条欧拉路包含所有边(当然前提是图依然连通)。若一个连通块内有 \(3\) 个或以下的点,均可以找到一条欧拉路包含所有边。根据贪心,我们得出结论:一个连通块只需删除最多一条边。
枚举删边后大力讨论一下即可。注意自环的处理与连通性的判定。
UOJ406 [IOI2018]排座位
对于一个编号 \(t\),我们将所有 \(0 \thicksim t\) 的所有格子染成黑色,其余格子为白色,那么若 \(t\) 是合法的,所有的黑色格子必须要构成一个完整的矩阵。更形式化地,当且仅当存在且仅存在 \(4\) 个 \(2 \times 2\) 的子矩阵满足其中只有一个黑色格子,且不存在 \(2 \times 2\) 的子矩阵满足其中存在 \(3\) 个黑色格子。
对于一个 \(2 \times 2\) 的子矩阵,若四个格子的编号分别为 \(a, b, c, d(a < b < c < d)\),那么当 \(t \in [a, b)\) 时,该 \(2 \times 2\) 的子矩阵满足只有一个黑色格子,当 \(t \in [c, d)\) 时,该 \(2 \times 2\) 的子矩阵满足有 \(4\) 个黑色格子。因此,我们可以以 \(t\) 为下标建线段树,那么每一个 \(2 \times 2\) 的子矩阵的贡献转化为线段树区间修改即可。
如果我们将两种贡献记为 \(s_1\) 与 \(s_2\),那么对于一次询问,我们只需查询线段树内有多少个位置满足 \(s_1 = 4, s_2 = 0\) 即可。
直接维护一种权值对应的数量并不好做。不过注意到只要存在一个黑色格子必然有 \(s_1 \geq 4\)。因此,\(s_1 = 4\) 且 \(s_2 = 0\) 都是最小的可能的权值,我们只需维护最小值的数量即可。
对于一次交换操作,可能会影响到的子矩阵不超过 \(8\) 个,直接对每个子矩阵在线段树上暴力修改贡献即可。
nowcoder OI周赛4-提高组-C 战争
首先,冲突只可能有两种情况:
- 最小值相同的所有区间不存在交
- 整段区间都被一个或多个最小值更大的区间覆盖
我们考虑将所有区间按最小值排序。那么对于权值相同的区间,我们首先要判断这些区间是否有交,如果不存在交则不合法。接下来,由于最小值一定存在于这段交的区间内,因此我们把这个区间看成一个新的区间。如果这段区间也被权值更大的交区间所覆盖,则不合法。可以使用线段树或并查集来判断是否被覆盖。
不过仅仅这样处理是不能找到第一个不合法的描述的,因此还需对第一个不合法的描述进行二分。
luogu4934 礼物
由于显然有 \(a_i \& a_j \leq \min(a_i, a_j)\),因此满足 \(a_i \& a_j \geq \min(a_i, a_j)\) 当且仅当 \(a_i \& a_j = \min(a_i, a_j)\)。因此原题转化为将给定的数划分成尽量少的集合,使得一个集合内不存在两个数满足一个数为另一个数的子集。
- Dilworth 定理:偏序集最小链覆盖等于最长反链。
- Dilworth 定理的对偶定理:偏序集最小反链覆盖等于最长链。
在这里,使用 Dilworth 定理的对偶定理,对所有数建图:若 \(a \subseteq b\),则连边 \(a \rightarrow b\)。那么最少划分集合数即为该图的最长链。可以拓扑排序,也可以直接 \(O(2^kk)\) 子集 dp。
BZOJ1095 [ZJOI2007]捉迷藏
直接扔掉点分治。
可以用线段树维护直径。
将树的 dfs 序映射到线段树上,假设一个结点有两个子结点,且已知这两个子结点对应的子树的直径和直径的两个端点,那么合并后该结点对应的子树的直径的两个端点一定是这四个端点的其中两个。因此对于一个结点,直接合并所有的子树,这样一直递归到根,我们就可以求出整棵树的直径了。
不难将子树推广到任意点集。这样,对于线段树上的两个结点也可以以相同的方式合并。
于是这个题还能稍稍加强一下,每次询问可以不一定是整棵树,而是以某个结点为根的一棵子树。
在结点合并的时候,我们需要求两点间的距离,需要用到 \(\rm lca\),因此单次修改操作的复杂度将会是 \(O(\log^2n)\) 的。使用 RMQ 求 \(\rm lca\) 即可将单次操作的时间复杂度降至 \(O(\log n)\)。
luogu3676 小清新数据结构题
我们不妨令原树的根为 \(1\),首先若没有换根操作,此题很好做,修改一个结点只需要修改该结点到根的路径上所有结点的子树权值和的平方即可,这里不再赘述。
接下来考虑换根。假设指定的根为 \(u\),结点 \(1\) 到结点 \(u\) 的路径上的点依次为 \(p_1, p_2, ... , p_k\),令以 \(1\) 为根,这 \(k\) 个点中的第 \(i\) 个点的子树权值和为 \(a_i\),以 \(u\) 为根,这 \(k\) 个点中的第 \(i\) 个点的子树权值和为 \(b_i\),若以 \(1\) 为根的答案为 \({\rm ans}_1\),以 \(u\) 为根的答案为 \({\rm ans}_u\),那么有:
\[\begin{aligned} {\rm ans}_u = {\rm ans}_1 - \sum_{i = 1}^k a_i^2 + \sum_{i = 1}^k b_i^2\end{aligned}\]
由于当 \(i < k\) 时,\(b_i = a_1 - a_{i + 1}\),因此有:
\[\begin{aligned} {\rm ans}_u &= {\rm ans}_1 - \sum_{i = 1}^k a_i^2 + \left(\sum_{i = 1}^{k - 1} {(a_1 - a_{i + 1})^2}\right) + b_k \\ &= {\rm ans}_1 - \sum_{i = 1}^ka_i^2 + \left(\sum_{i = 2}^{k} {a_1^2 - 2a_1a_{i} + a_{i}^2}\right) + a_1 \\ &= {\rm ans}_1 - \sum_{i = 2}^k a_i^2 + \sum_{i = 2}^k a_i^2 + \sum_{i = 2}^k a_1^2 - 2a_1a_i \\ &={\rm ans}_1 + \sum_{i = 2}^ka_1^2 - 2a_1a_i \\ &= {\rm ans}_1 + (k - 1)a_1^2 - 2a_1\sum_{i = 2}^k a_i\end{aligned}\]
那么显然,这个式子也是可求的。这样,我们就可以用树链剖分+线段树维护子树点权和与和的平方解决此题。如果将 \({\rm ans}_1\) 当做全局变量记录,甚至没有必要维护子树权值和的平方,只需维护子树点权和,用树状数组即可实现。
BZOJ3243 [NOI2013]向量内积
使用随机化算法。
当 \(k = 2\) 时,对于一个 \(i\),若向量 \(i\) 与所有向量 \(j\) 的内积 \({\rm mod}\ 2\) 的值均为 \(1\),则有 \(s_i \equiv i - 1\ ({\rm mod}\ 2)\)(\(s_i\) 为向量 \(i\) 与所有向量 \(j\) 的内积\(\bmod 2\) 的值的和)。反过来,如果不满足 \(s_i \equiv i - 1\ ({\rm mod}\ 2)\),则必然存在一个 \(j\),满足向量 \(i\) 与向量 \(j\) 的内积 \(\rm mod\ 2\) 的值为 \(0\)。这样,我们就可以随机排列之后,依次求每个 \(i\) 对应的 \(s_i\)。若找到不满足 \(s_i \equiv i - 1\ ({\rm mod}\ 2)\) 的 \(i\) 后暴力查找 \(j\) 即可。求所有 \(s_i\) 的时间复杂度为 \(O(nd)\)。
不过这种做法不能拓展到 \(k = 3\) 的情况,因为向量 \(i\) 与向量 \(j\) 的内积在 \({\rm mod}\ 3\) 不等于 \(0\) 时会有 \(1, 2\) 两种取值。不过注意到 \(1, 2\) 平方后 \({\rm mod}\ 3\) 均为 \(1\),因此我们可以将 \(s_i\) 的定义改为向量 \(i\) 与所有向量 \(j\) 的内积\(\bmod 2\) 的值的平方和,剩下的处理及判断方法就和 \(k = 2\) 时一模一样了。此时求所有 \(s_i\) 的时间复杂度为 \(O(nd^2)\)。
UVaLive7078 Yue Fei's Battle
首先,我们记 \(f_i\) 为最深结点深度为 \(i\) 的异构有根二叉树数量,若根节点深度为 \(1\),那么有:
\[f_i = \begin{cases} 1, & i \leq 1 \\ f_{i - 1} \times s_{i - 2} + \binom{f_{i - 1}}{2} + f_{i - 1}, & i > 1\end{cases}\]
其中,\(s_i\) 表示 \(\sum_\limits{i = 0}^{i} f_i\)。当 \(i > 1\) 时,考虑最深结点深度为 \(i\) 的有根二叉树的根节点的两棵子树,显然可以分三种情况讨论:一棵深度为 \(i - 1\),另一棵深度小于 \(i - 1\)(方案数为 \(f_{i - 1} \times s_{i - 2}\))、两棵深度均为 \(i - 1\) 但异构(方案数为 \(\binom{f_{i - 1}}{2}\))、两棵深度均为 \(i - 1\) 且同构(方案数为 \(f_{i - 1}\)),故有上式。
接下来,本题我们按 \(k\) 的奇偶性分类讨论。为了方便,以下我们记 \(n = \lfloor \frac{k}{2} \rfloor\)。
- 当 \(k\) 为奇数时,显然所有最长路径过定点,且删掉该定点后恰好得到两棵最深结点深度均为 \(n\) 的有根二叉树。于是答案为 \(\binom{f_{n}}{2} + f_n\)(两棵同构+两棵异构)。
- 当 \(k\) 为偶数时,显然所有最长路径过定边,且删掉该定边后必得到两棵最深结点深度为 \(n\) 的有根二叉树,同时还会得到最多一棵最深结点深度不超过 \(n\) 的有根二叉树(包括空二叉树)。若得到一棵最深结点深度小于 \(n\) 的有根二叉树,答案为 \(s_{n - 1} \times (\binom{f_n}{2} + f_n)\);若得到三棵最深结点深度均为 \(n\) 的有根二叉树,答案为 \(f_n + \binom{f_{n}}{2} \times 2 + \binom{f_n}{3}\)(三棵同构+两棵同构+三棵异构)。
CF1078D Chattering
为了方便,可以将原序列在左边和右边各复制一次,这样将环变为链,方便处理。
我们可以使用倍增,记录每个点 \(p\) 扩展 \(2^k\) 次后向左向右所能到达的最远位置,可以用 \(k\) 棵线段树维护这一信息。这样我们就能按 \(k\) 从小到大更新线段树,若要得到第 \(i\) 棵树中位置 \(p\) 能扩展到的最大区间,可以在第 \(i - 1\) 棵树中查询 \(p\) 能到的最大区间(记为 \([l, r]\)),再在第 \(i - 1\) 棵线段树中查询 \([l, r]\) 能扩展到的最大区间,得到的区间即为所求区间。使用单点修改、区间查询最值线段树即可。
LOJ2799 [CCC 2016]生命之环
我们将原串下标从 \(0\) 至 \(n - 1\) 编号,用 \(s_p\) 表示位置 \(p\) 上的数字。首先有如下结论:
对于一个位置 \(p\),若 \(s_p\) 在经过 \(c(c = 2^k)\) 次变换后为 \(1\),当且仅当环上从 \(p\) 开始左数第 \(c\) 个位置上的数字与右数第 \(c\) 个位置上的数字不相同。
证明如下:
首先,当 \(c = 1\)(即 \(k = 0\))时显然成立。
考虑 \(c = 2\)(即 \(k = 1\))。
- 考虑 \(p\) 左数 \(2\) 个位置与右数 \(2\) 个位置的值不一样,不妨设 \(p = 2\),原串为 \(0???1\)。由于 \(s_2\) 只有 \(0/1\) 两种取值,换句话说,\(s_2\) 必然与 \(s_0, s_4\) 的其中一个一样,与另一个不一样,这样,我们在经过一次变换后得到的 \(s_1\) 与 \(s_3\) 也不一样,故 \(2\) 次变换后 \(s_2\) 必为 \(1\)。
- 考虑 \(p\) 左数 \(2\) 个位置与右数 \(2\) 个位置的值一样,也不妨设 \(p = 2\),原串为 \(0???0\)。由于 \(s_2\) 无论取 \(0/1\),都必然为:要么和 \(s_0, s_4\) 都一样,要么和 \(s_0, s_4\) 都不一样,这样经过一次变换后得到的 \(s_1\) 与 \(s_3\) 也一样,故 \(2\) 次变换后 \(s_2\) 必为 \(0\)。
故 \(c = 2\) 时结论成立。
注意在上述 \(c = 2\) 的分析过程中,无论 \(s_2\) 取何值,我们都能得到两个 \(c = 1\) 的子问题,且若两端值不同,这两个子问题的结果也必然不同;若两端值相同,这两个子问题的结果也必然相同。由此可以推广得到:通过 \(c = 2^k\),我们可以得到两个 \(c = 2^{k - 1}\) 的子问题。这样当 \(k\) 更大时,结论显然也是成立的。
有了该结论后,本题就可以通过将 \(T\) 拆位后在 \(O(n \log T)\) 的时间内解决了。
nowcoder Wannafly挑战赛4-F 线路规划
倍增并查集的具体实现方法可参考 [SCOI2016]萌萌哒。关于其时间复杂度,这里做简要说明:对于一幅由 \(n\) 个结点构成的图,其生成树只会有 \(O(n)\) 条边,相应地,最多也只会做 \(O(n)\) 次合并。虽然倍增并查集的单次合并操作最坏情况下可能达到 \(O(n)\),但是由于合并只在同层图间进行,因此 \(\log\) 层图最多也只会有 \(O(n \log n)\) 次合并,因此总时间复杂度是 \(O(n\alpha \log n)\) 的。
回归此题,本题将倍增并查集从序列上转移到了树上,不过做法是一样的,此处的倍增并查集数组 \(f_{u, d}\) 的意义就变为了从结点 \(u\) 开始往上的 \(2^d\) 个连续结点对应的并查集。合并时只需要在 \(d = 0\) 时顺便维护结点及边权信息即可。
BZOJ4140 共点圆加强版
对于一个定点 \((x_0, y_0)\),若它在过原点的圆(圆心坐标为 \((x, y)\))内,必然满足 \((x_0 - x)^2 + (y_0 - y)^2 \leq x^2 + y^2\),即 \(y \geq -\frac{x_0}{y_0} x + \frac{x_0^2 + y_0^2}{2y_0}\) 或 \(y \leq -\frac{x_0}{y_0} x + \frac{x_0^2 + y_0^2}{2y_0}\),显然这对应一个半平面,因此原题转化为给定一些点,每次询问所有点是否在某个半平面内。可以维护所有点构成的凸包,在凸包上二分找关键点后直接判断即可。一个简单的做法是离线所有操作,使用 CDQ 分治在 \(O(n \log n)\) 的时间内解决。
然而此题强制在线,不过我们依然有避免使用高级数据结构的简单做法:使用许昊然在 2013 年国家集训队论文 中提到的二进制分组算法。将所有点分成最多 \(\log n\) 组,每组维护上下凸包。修改时暴力构建新的组并维护凸包,查询时在每一组的上凸包或下凸包内二分判断即可。时间复杂度 \(O(n \log^2 n)\)。
CF1053B Vasya and Good Sequences
我们记一段区间内所有数在二进制下 \(1\) 的个数和为 \(s\)。一段区间合法需满足的条件为:
- \(s\) 为偶数
- 区间内不存在一个数在二进制下 \(1\) 的个数超过 \(\frac{s}{2}\)(否则它的每一位无法都和其他的数配对)
对于条件 1 我们很好处理,只需要记录前缀和为奇数与为偶数的数量。考虑如何处理条件 2。注意到所有 \(a_i\) 满足 \(a_i \geq 1\),换句话说,每一个 \(a_i\) 都会有至少一个二进制位为 \(1\),又由于 \(a_i \leq 10^{18}\),其二进制下 \(1\) 的数量不会超过 \(60\) 个,因此当区间长度足够大时,条件 2 一定会满足。这样,我们可以枚举右端点 \(r\),对于满足 \(r - l\) 不超过某个阈值的左端点 \(l\) 可以暴力枚举,剩余部分直接加上前缀和为奇数或为偶数的数量即可。
luogu2664 树上游戏
使用点分治。对于每层分治的重心 \(u\),暴力求结点 \(u\) 到点分树上以 \(u\) 为根的子树内所有结点的 \(s\) 的值。接下来,难点在于如何快速地算出 \(u\) 的各棵子树之间的贡献。
直接求 \(s\) 不太方便,我们考虑每种颜色对每个结点造成的贡献。记录 \(g_i\) 表示结点 \(u\) 到结点 \(i\) 的路径上所出现的不同的颜色数量,\({\rm size}_i\) 表示当前以 \(i\) 为根的子树结点数目,那么对于 \(u\) 的某一个儿子 \(v\),以 \(v\) 为根的子树内的所有结点 \(i\),首先会有 \(({\rm size}_u - {\rm size}_v) \times g_i\) 的贡献,因为显然其他子树内的结点到结点 \(i\) 都会造成 \(g_i\) 的贡献。接下来考虑没有在结点 \(u\) 到结点 \(i\) 的路径上出现过的颜色的贡献。我们记录 \(f_j\) 表示当前以 \(u\) 为根的点分树内所有「颜色为 \(j\) 且从 \(u\) 到该结点的路径上不存在其他颜色为 \(j\) 的结点」的结点的 \({\rm size}\) 之和。处理 \(u\) 的每棵子树时,我们需要除去当前子树内已经出现过的颜色对 \(f_j\) 的贡献。在这个过程中,维护 \(\sum f_j\) 的值,用其更新子树内每个点即可。
在单层分治内,\(f_i, g_i\) 等信息的维护以及每个结点贡献的计算都能够线性实现,因此总时间复杂度为 \(O(n \log n)\)。
BZOJ4785 [ZJOI2017]树状数组
我们记录 \(\sum_\limits{k = 1}^i A_k\) 为 \({\rm pre}_i\)(即前缀和),\(\sum_\limits{k = i}^n A_k\) 为 \({\rm suf}_i\)(即后缀和)。
不难发现,代码中的 Find
函数求的正是后缀和。因此按照正确的写法,我们求出的是 \({\rm pre}_r - {\rm pre}_{l - 1}\),即 \(\sum_\limits{i = l}^r A_i\),而按照错误的写法,求出的是 \({\rm suf}_{l - 1} - {\rm suf}_r\),即 \(\sum_\limits{i = l - 1}^{r - 1} A_i\)。两者相等只需 \(A_{l - 1} = A_r\) 即可。因此,原题的询问操作转化为给定 \(l, r\),求 \(A_{l - 1}\) 与 \(A_r\) 相等的概率。
为了方便,以下将询问中的 \(l - 1\) 记为 \(a\),\(r\) 记为 \(b\)。
我们记 \(A_a\) 与 \(A_b\) 相同的概率为 \(p\),初始 \(p = 1\)。对于所有修改的区间 \([x, y]\),我们令该修改操作不会导致 \(A_a\) 或 \(A_b\) 其中之一发生变化的概率为 \(q\),这样,每次修改操作后相等的概率 \(p'\) 就应为 \(p \times q + (1 - p) \times (1 - q)\)。考虑一个修改区间会对哪些询问区间造成多少的贡献,那么有:若 \(a \in [x, y]\) 与 \(b \in [x, y]\) 均不满足,那么 \(q = 1\);若满足其中之一,那么 \(q = 1 - \frac{1}{y - x + 1}\);若均满足,那么 \(q = 1 - \frac{2}{y - x + 1}\)。由于新的概率 \(p' = p \times q + (1 - p) \times (1 - q)\) 这一式子满足交换律与结合律(因此甚至可以同时维护 \(A_a\) 与 \(A_b\) 相同与不同的概率,并用矩阵转移),因此,我们就能够用二维线段树维护 \(q\),\(a\) 与 \(b\) 分别对应了两维。每次修改分区间讨论,在第一维的对应区间的第二维的结点上打永久化标记;每次查询则直接统计所有第一维经过区间的第二维结点的标记贡献即可。
不过由于本题的 Find
函数对 \(0\) 位置进行了特判,因此当 \(a = 0\)(即询问左端点为 \(1\))时还需单独维护,这里不再赘述。
luogu4131 [WC2005]友好的生物
由于友好程度的计算式中包含绝对值,又由于 \(K \leq 5\),因此我们考虑将绝对值拆开,暴力枚举所有的符号可能,这样我们能够将生物 \(i\) 与 \(j\) 的友好程度拆开,每种生物独立计算属性和。
我们记生物 \(i\) 的第 \(x\) 种属性值为 \(a_{i, x}\)。
考虑将所有生物按照 \(a_{i, K}\) 的值从小到大排序,这样能够保证所有 \(a_{i, K}\) 与 \(a_{j, K}(j < i)\) 之差均为正。
接下来,我们按顺序依次处理所有生物,那么对于生物 \(i\),我们枚举 \(2^{K - 1}\) 种符号情况的值。我们记 \(f_S\) 表示前 \(i - 1\) 种生物中符号情况为 \(S\) 时的属性和的最大值。这样,对于每种符号情况,我们只需要用当前生物 \(i\) 的属性和+与之相反的符号情况的 \(f\) 值更新答案,在依次处理每个生物时,顺便维护更新 \(f\) 即可。
考虑其正确性:由于前 \(K - 1\) 种属性在友好程度中的系数均非负,因此对于生物 \(i, j\),\(|a_{i, x} - a_{j, x}|\) 取得最优值当且仅当 \(\max\{a_{i, x}, a_{j, x}\}\) 的符号为 “\(+\)”,而 \(\min\{a_{i, x}, a_{j, x}\}\) 的符号为 “\(-\)”,其他符号情况的值均不会超过该最优值。对于第 \(K\) 种属性,虽然在友好程度的计算式中系数非正,但由于已经按属性值从小到大排序,因此避免了对该项的讨论。
时间复杂度 \(O(n \log n + n 2^k k)\)。
BZOJ4285 使者
首先考虑其不带增删操作的版本,即预先给定了所有的跳跃点。
将原树有根化后,对于一次询问 \((x, y)\),记结点 \(x\) 与结点 \(y\) 的 \({\rm lca}\) 为结点 \(c\)(结点 \(x\) 的深度小于结点 \(y\))。我们分两种情况讨论:
- 若结点 \(c\) 不为结点 \(x\),那么从结点 \(x\) 到结点 \(y\) 的合法路径经过的跳跃点 \((u, v)\) 必须满足结点 \(u, v\) 分别在以 \(x\) 为根的子树内和以 \(y\) 为根的子树内。
- 若结点 \(c\) 为结点 \(x\),设路径 \((x, y)\)上结点 \(x\) 的子结点为结点 \(z\),那么从结点 \(x\) 到结点 \(y\) 的合法路径经过的跳跃点 \((u, v)\) 必须满足结点 \(u, v\) 的其中之一在以 \(y\) 为根的子树内,另一个不在以 \(z\) 为根的子树内。
一棵子树的 dfs 序为一段连续的区间,我们将问题转移到 dfs 序上,令结点 \(u\) 的 dfs 序为 \(p_u\),若我们将一个跳跃点 \((u, v)\) 看成二维平面上的一个点 \((p_u, p_v)\)(或 \((p_v, p_u)\)),那么一次询问转化为求一个或两个矩形内的点的数量(因为不在一棵子树内可以转化为至多两个连续的 dfs 序区间),可以将所有询问离线后使用树状数组解决。
考虑带增删操作的版本。由于题目依旧支持离线做法,因此使用 CDQ 分治即可。
CF682E Alyona and Triangles
假设给定的 \(n\) 个点中,能构成面积最大的三角形的三个点分别为 \(A, B, C\),那么可以证明的是,以这三点为三边上中点的三角形一定包含给定的所有点,同时,该三角形面积恰好等于 \(4S_{\triangle ABC}\)。
这样,我们只需要找出 \(n\) 个点中构成三角形面积最大的三个点。\(O(n^2)\) 旋转卡壳即可。
luogu4747 [CERC2017]Intrinsic Interval
参考了 wxh 的做法。
对于原序列中相邻的两个数 \(p_i\) 与 \(p_{i + 1}\),如果一个询问区间包含了这两个数,那么也应包含 \((p_i, p_{i + 1})\) 内的所有数。找出这些数在原序列中出现的最左边和最右边的位置 \(l, r\),将原序列中每两个相邻的位置视作一个结点后,让结点 \(i\) 向 \([l, r)\) 的所有点连边,表示若询问区间包含位置 \(i\) 与 \(i + 1\),也应包含位置 \([l, r]\)。那么对于一个询问区间 \([a, b]\),答案区间的左端点就是 \([a, b)\) 内的所有结点可以到达的编号最小的结点的编号,答案区间的右端点就是可以到达的编号最大的结点编号 \(+ 1\)。其正确性显然。
由于连边的形式是单个结点向一段区间连边,故可以用线段树优化。注意到这是一个带环的有向图,因此需要用 Tarjan 将强连通分量缩成点,使整幅图无环后,再求出每个结点所能到达的所有结点的编号最小值与最大值。最值也可用一棵线段树维护,查询直接在线段树上区间查询即可。