【题解】四月训练日记
CF1709E. XOR Tree
*2400 Code
注意到操作时改成的正整数没有大小限制,不妨改成 \(2^{k}\)(\(k\) 充分大),这样经过该点的路径的权值绝对不可能为 \(0\)。
指定一个根节点(不妨为 \(1\)),假定路径 \(x\leftrightarrow y\) 是坏的(也就是异或和为 \(0\)),那么容易说明修改 \(z=\text{LCA}(x,y)\) 是最优的。
考虑这么一个过程:从根节点开始向下 dfs,回溯时判断当前节点 \(z\) 是否能作为一条坏的路径的 \(\text{LCA}\)。若能,答案 \(+1\);否则不做修改。
问题转换为如何进行这个判定。设 \(f_x\) 代表从根节点开始的前缀异或和,即路径 \(1\leftrightarrow x\) 的权值。那么,路径 \(x\leftrightarrow y\) 是坏的等价于 \(f_x\oplus f_y\oplus a_{\text{LCA}(x,y)}=0\)。
对每一个顶点 \(z\) 维护一个 std::set
,存储以 \(z\) 为根的子树里的节点的 \(f\) 集合。这样当我们合并 \(z\) 的一个儿子(设为 \(p\))的信息时,只用遍历 \(z,p\) 中较小的一个集合,在另一个集合里查有没有符合要求的元素。
若当前节点需要修改,就清空当前节点的 std::set
,否则合并儿子的信息。
这是一个启发式合并的过程,时间复杂度 \(O(n\log^2 n)\)。
CF1981D. Turtle and Multiplication
*2400 Code
当所有 \(a_i\) 都是质数时,\(a_i\cdot a_{i+1}\not=a_j\cdot a_{j+1}\) 的充要条件是无序对 \((a_i,a_{i+1})\) 和无序对 \((a_j,a_{j+1})\) 不同。当 \(a_i\) 不都是质数时,充要条件会退化成必要条件,更劣,故优先思考 \(a_i\) 都是质数时是否能构造。
将无序对 \((a_i,a_{i+1})\) 看作一条无向边,那么问题转换为找到一个最小的 \(m\),满足 \(m\) 个点构成的完全图存在一条覆盖 \(n-1\) 条边(每条边至多被覆盖一次)的路径。
当 \(m\) 为奇数时,图上所有顶点的度数都是偶数,存在一条长 \(\frac{m(m-1)}{2}+m\) 的欧拉回路(\(+m\) 是因为每个点都有自环,算一条边)。
当 \(m\) 为偶数时,图上所有顶点的度数都是奇数。无向图存在欧拉路径的条件是有 \(0/2\) 个点是奇度点,其它为偶度点。考虑删边,只留下两个奇度点,一种留下最多边的方式是删 \((2,3),(4,5),(6,7),\ldots,(m-2,m-1)\)。剩余边数是 \(\frac{m(m-1)}{2}+m-\frac{m}{2}+1\)。
二分出最小满足条件的 \(m\),构造出对应的 \(m\) 个点的完全图(若 \(m\) 是偶数还要按上述规则删边),跑出一条欧拉路径。若路径上第 \(i\) 个点是 \(x\),对应到序列上 \(a_i\) 就是第 \(x\) 小的质数。
当 \(m=1500\) 时,构造出的图有 \(1125001>10^6\) 条边,而第 \(1500\) 小的质数是 \(12553<3\cdot 10^5\),满足条件。
时间复杂度 \(O(n)\)。
CF1981E. Turtle and Intersected Segments
*2600 Code
对于三条两两相交的线段 \([l_1,r_1,a_1],[l_2,r_2,a_2],[l_3,r_3,a_3]\),设 \(a_1\le a_2\le a_3\),那么可以仅保留边 \(1\leftrightarrow 2,2\leftrightarrow 3\)。(因为 \(|a_1-a_3|=|a_1-a_2|+|a_2-a_3|\),选第 \(3\) 条边肯定不优)
不难发现对于每一条线段 \([l_i,r_i,a_i]\),我们只用保留两条边:
- 与该线段相交的线段中,权值(设为 \(a_j\))最大且满足 \(a_j\le a_i\) 的边。
- 与该线段相交的线段中,权值(设为 \(a_j\))最小且满足 \(a_j\ge a_i\) 的边。
扫描线,维护一个 std::set
,扫描到一条线段的左端点时就把线段的权值加进去,扫描到右端点时就把对应的权值删掉。保留的边相当于线段在容器中的前驱和后继。
最终处理出的侯选边有 \(O(n)\) 条,跑最小生成树即可。
时间复杂度 \(O(n\log n)\)。
abc399e. Replace
连边 \(S_i\to T_i\)。
首先每个点至多有一条出边,否则 -1
。\(26\) 个点都有入度,也为 -1
。
否则答案的下界是图上的边数(不含自环)。
对于一个环,分两种情况:
- 环上存在入度为 \(2\) 的点。说明存在一条边 \(x\to y\) 满足 \(y\) 在环上而 \(x\) 不在。设 \(y\) 的另一条入边是 \(z\to y\),此时可以花 \(1\) 的代价将 \(z\) 改为 \(x\),破环成链,且不花费额外次数(即用 \(1\) 次操作断了一条边,与预设 "答案是图上的边数" 相符)。
- 环上所有点入度为 \(1\)。此时只能将环上任意一点 \(x\) 替换为图中的一个孤点,最后再改回来,花费了 \(1\) 点额外次数。
于是答案是图上的边数 \(+\) 第二类环的数量。
时间复杂度 \(O(n)\)。
CF1139E. Maximize Mex
*2400 Code
考虑没有人离开社团的情况。此时二分答案,设二分的 \(\text{mex}\) 是 \(mid\),那么只需要保留潜力值 \(<mid\) 的学生。
建出一个二分图,左部图是 \(m\) 个社团,右部图对应 \(0\sim mid - 1\) 这 \(mid\) 个潜力值。对于一个学生,我们可以连出一条边,最终只要看最大匹配是否为 \(mid\)。
若有学生离开了,相当于删掉一条边,这是不好处理的。但我们想到 Dinic 可以动态加边,于是离线下来倒着做。
但每加一条边就要重新二分枚举 \(\text{mex}\) 就太低效了。注意到加边的时候 \(\text{mex}\) 只增不减,换句话匹配数只增不减。我们可以从 \(1\) 开始枚举 \(\text{mex}\),每次将 \(p[i]=\text{mex}-1\) 的学生加到图上,若匹配数恰好为 \(\text{mex}\),就 \(\text{mex}\leftarrow \text{mex}+1\),重复这个流程。
此时,一个学生 \(i\) 加入社团,分两种情况处理:
- 加入时枚举的 \(\text{mex}\ge p[i]\)。直接加边即可。
- 加入时枚举的 \(\text{mex}<p[i]\)。将学生 \(i\) 加进备选名单里,等 \(\text{mex}\) 枚举到的时候再加边。
时间复杂度 \(O(\text{MaxFlow}(m, n))\)。
CF1746F. Kazaee
*2800 Code
先将所有数(包括原有的 \(a_i\) 与每次修改后的 \(x\))进行离散化。
一个暴力的做法是对每个数都维护一个树状数组,这样整道题能在 \(O(n^2+qn\log n)\) 内解决。
面临的困难无非只有一点:对于一个区间,时间复杂度不允许我们 check 区间里每一个数的出现次数。
一个关键点是,一段区间中,如果所有数字的出现次数都是 \(k\) 的倍数,其出现次数之和也一定为 \(k\) 的倍数,但这是必要不充分条件。
随机化,在值域内随机选出 \(B\) 个子集,对于一个询问,逐一 check 每一个子集,看每个子集里的数的出现次数之和是否为 \(k\) 的倍数。
而单点修改时,遍历这 \(B\) 个子集,若当前子集包含修改前/修改后的数,就相应在树状数组上修改。
为了保证正确性,每个子集按照以下方式随机:
- \(\forall i\in [1,W]\),\(i\) 有 \(\dfrac{1}{2}\) 的概率选进子集。其中 \(W\) 为离散化后的值域。
错误率分析:最坏情况下,判错当且仅当存在一对数 \(x,y\),满足 \(k\mid cnt_x+cnt_y\) 且 \(k\not\mid cnt_x\),\(k\not\mid cnt_y\)。四种情况:选 \(x\) 没选 \(y\),选 \(y\) 没选 \(x\),没选 \(x\) 没选 \(y\),选 \(x\) 选 \(y\),它们在概率上各占 \(\dfrac{1}{4}\),其中仅第三第四种会犯错,占 \(\dfrac{1}{2}\)。取 \(B=30\),错误率就是 \(\dfrac{1}{2^{30}}\),足够低了。
时间复杂度 \(O(nB\log n+qB\log n)\)。
abc401f. Add One Edge 3
记 \(G\) 为树 \(1\),\(H\) 为树 \(2\)。
记 \(d_1,A_1,A_2\) 为 \(G\) 的直径及其两个端点,\(d_2,B_1,B_2\) 为 \(H\) 的直径及其两个端点。
记 \(f_x/g_x\) 为以 \(G/H\) 中的点 \(x\) 为端点的最长的路径的长度,显然有 \(f_x=\max(dis(A_1,x),dis(A_2,x))\),\(g_x=\max(dis(B_1,x),dis(B_2,x))\)。
对于一条连接了 \(G\) 中点 \(i\) 和 \(H\) 中点 \(j\) 的边,新图直径变为 \(\max(\max(d_1,d_2),f_i+g_j+1)\)。
将 \(f_x,g_x\) 升序排序,枚举 \(f_i\),就能二分或双指针求出有多少个满足 \(f_i+g_j+1>\max(d_1,d_2)\) 的 \(g_j\),贡献就是一段 \(g\) 的后缀和。
时间复杂度 \(O(n\log n)\)。
CF1749E. Cactus Wall
*2400 Code
转化:相当于寻找一条 #
构成的路径,这条路径从第一列开始,到最后一列结束,且每次只能走对角线的四个方向。
先把图上所有可以放置 #
的位置找出来(包括原来就有的 #
),称作关键点。
建图,源点 \(S\) 向第一列的关键点连边,每个关键点向四个对角线方向的关键点连边,最后一列的关键点向汇点 \(T\) 连边。
一条边 \((u,v)\) 的边权取决于 \(v\),若 \(v\) 为汇点或原来就有 #
的位置,边权就是 \(0\);否则边权是 \(1\)(代表需要在此处新放置一个 #
)。
跑最短路即可,记一下路径方案也就有了。
时间复杂度:\(O(nm\log nm)\)。若使用 01bfs 还可以省去 \(\log\)。
CF2096E. Wonderful Teddy Bears
*2400 Code
将 B
看作 \(0\),P
看作 \(1\)。
对一个长为 \(3\) 的子串操作,分为以下四种情况。
- \(010\to 001\);
- \(100\to 001\);
- \(101\to 011\);
- \(110\to 011\)。
我们将操作 \(1,3\) 归为一类,称为 \(A\);操作 \(2,4\) 归为一类,称为 \(B\)。
之所以这么分,是因为观察到如下性质:
- \(A\) 类操作能将逆序对数 \(-1\),而 \(B\) 类操作能将逆序对数 \(-2\)。
- \(A\) 类操作能改变一个 \(0\) 的下标奇偶性,而 \(B\) 类操作不能。
令 \(c_0,c_1\) 分别表示序列中 \(0/1\) 的个数,\(rev\) 表示逆序对数,\(tot\) 表示下标为偶数的 \(0\) 的数量。
想象一个排好序的的 \(01\) 串:有 \(\left\lfloor\frac{c_0}{2}\right\rfloor\) 个 \(0\) 的下标为偶数(1-index)。
那么可以先用 \(\left|tot-\left\lfloor\frac{c_0}{2}\right\rfloor\right|\) 次 \(A\) 类操作调整奇偶性,再用 \(B\) 类操作减少逆序对数。
可以预见的是调整奇偶性后逆序对数一定是偶数,故最后不必再用 \(A\) 类操作减少逆序对数。
答案是 \(\left|tot-\left\lfloor\frac{c_0}{2}\right\rfloor\right| + \dfrac{(rev-\left|tot-\left\lfloor\frac{c_0}{2}\right\rfloor\right|)}{2}=\dfrac{rev+\left|tot-\left\lfloor\frac{c_0}{2}\right\rfloor\right|}{2}\)。
时间复杂度 \(O(n)\)。
CF1977D. XORificator
*2300 Code
注意到当我们钦定某个点 \((x,y)\) 为那一列(即第 \(y\) 列)唯一的 \(1\) 时,每一行是否需要翻转就被唯一确定了(或者说整个矩阵都被确定了)。
考虑枚举每个点作为那一列唯一的 \(1\),问题转换为如何快速知道该状态下有多少列仅有一个 \(1\)。
反向思考,钦定一个点作为那一列唯一的 \(1\) 时,把此时的 XORificator 记录下来(题解里用的 Zobrist hashing,implement 非常精悍短小),答案就是出现次数最多的 XORificator 的出现次数。
时间复杂度 \(O(nm\log nm)\)。
CF1622D. Shuffle
*2000 Code
要求本质不同看起来十分困难,但有个 trick 是你枚举所有区间,然后钦定这个区间的左端点和右端点都一定发生了变化,这样计数不重不漏,考虑起来就轻松很多。
先特判掉整个串的 \(1\) 都不足 \(k\) 个的情况。
首先,枚举的区间需要满足 "区间内 \(1\) 的个数 \(\le k\)",为什么是小于等于?因为我们实际操作的区间恰有 \(k\) 个 \(1\),但相对原来发生变化的区间可以是一个子集。
接着,区间两侧的数必须发生变化,非两侧的数任意排列,贡献就是一个组合数。
时间复杂度 \(O(n^2)\)。
CF1622E. Math Test
*2200 Code
trick:拆绝对值。\(|x_i-r_i|\) 可以拆成 \(x_i-r_i\) 和 \(r_i-x_i\) 两种,时间复杂度允许我们 \(O(2^n)\) 枚举每一种拆法。
贪心,我们可以统计出每道题被多少个人解决了(如果那个人是 \(x_i-r_i\),\(r_i\) 的贡献是负的,就当作 \(-1\) 个人;反之 \(r_i-x_i\) 就看作 \(+1\) 个人),给被更多人解决的题赋值一个大的 \(p_j\)。
因为绝对值被拆掉了,\(\{p\}\) 确定之后最终答案也确定了,取 \(\max\) 即可。
时间复杂度 \(O(nm2^n)\)。
CF1354E. Graph Coloring
*2100 Code
注意到 \(1,3\) 作为一组,\(2\) 作为一组,组间连边组内不连边,构成二分图。
故 YES
的必要条件是给定的图的每一个连通分量均是二分图。
接着考虑数量限制:我们只用关心 \(2\) 的数量能否得到满足,\(2\) 满足了 \(1,3\) 自然满足。
设给定的图有 \(m\) 个连通分量,第 \(i\) 个连通分量有 \(L_i\) 个左部点,\(R_i\) 个右部点。
现在我们要对每个连通分量选出左部或者右部填 \(2\),另一部 \(1,3\) 任意填。
抽象出来相当于有 \(m\) 个集合,每个集合可以选 \(L_i\) 或 \(R_i\) 中的恰好一个,判断是否存在一种选择方案使得选出的 \(m\) 个数的总和是 \(n_2\)。
令 \(dp[i][j]\) 表示前 \(i\) 个集合选出的数是否能凑成 \(j\),还需另开一个数组记录方案。
时间复杂度 \(O(n^2)\)。
CF1354F. Summoning Minions
对于一个将来需要销毁的仆从,将它升级没有意义,故选择召唤之后马上销毁。
于是,最佳策略应该形如:
- 从 \(n\) 个仆从中选择 \(k-1\) 个召唤。
- 从剩下的 \(n-k+1\) 仆从中选择 \(n-k\) 个召唤后立即销毁。
- 召唤剩下的那 \(1\) 个仆从。
在第一步中,假设仆从 \(i\) 在第 \(j\) 个被召唤,则贡献是 \(a_i+b_i (j-1)\)。
在第二步中,仆从 \(i\) 被召唤的贡献固定为 \(b_i(k-1)\)。
在第三步中,仆从 \(i\) 被召唤的贡献为 \(a_i+b_i(k-1)\),可以和第一步的贡献合并。
建立二分图,左部点代表仆从,右部点代表被召唤时的顺序,问题转化为一个满二分图的最大权匹配,跑最大费用最大流即可。
时间复杂度 \(O(T\cdot \text{MinCostMaxFlow}(n, n^2))\)。
另一种方法是注意到在第一步中,选定的 \(k\) 个仆从(与第三步合并了,所以是 \(k\) 个)一定按 \(b_i\) 升序召唤。
令 \(dp[i][j]\) 表示前 \(i\) 个仆从选出 \(j\) 个放在第一步的最大答案。 \[ dp[i][j] = \max(dp[i-1][j]+b_i(k-1),dp[i-1][j-1]+a_i+b_i(j-1)) \] 回溯以记录方案。
时间复杂度 \(O(Tnk)\)。
CF555E. Case of Computer Network
*2800 Code
位于同一个边双连通分量中的点总是可以互相到达。(指总是存在一种可行的定向方案)
边双缩点,对于一组 \((s_i, d_i)\),若 \(s_i\) 和 \(d_i\) 在同一个边双内,则可以忽略。
否则,\(s_i\to d_i\) 上的边的方向就被固定了。(此处的 \(s_i,d_i\) 指的都是其所在边双的编号,下同)
固定一个根,对每个点维护两个标记 \(up\) 和 \(down\) 分别表示上下两个方向。
对于一组询问,\(s_i\to \text{LCA}(s_i,d_i)\) 上的点的 \(up\) 标记 \(+1\),\(\text{LCA}(s_i,d_i)\to d_i\) 上的点的 \(down\) 标记 \(+1\),这个操作可以用树上差分简单实现。
最后,若有一个点同时有非零的 \(up\) 和 \(down\) 标记,就是 No
。
此题有若干细节:
- 图不连通,缩点后是一个森林,处理 LCA 时要小心。
- 若询问中的两个点不在一个连通分量内,直接就是
No
。 - 有重边。若两个点之间有重边,则它们属于同一个边双。
时间复杂度 \(O((n+q)\log n)\)。
abc399f. Range Power Sum
令 \(s_i=\sum\limits_{j=1}^{i} s_j\),则: \[ \begin{align} \sum_{1\le l\le r\le N}\left(\sum_{l\le i\le r}a_i\right)^k &= \sum_{l=1}^{n}\sum_{r=l}^{n}\left(s_r-s_{l-1}\right)^k \\ &= \sum_{l=1}^{n}\sum_{r=l}^{n}\sum_{i=0}^{k}(-1)^{k-i}\binom{k}{i}s_r^{i}s_{l-1}^{k-i} \\ &= \sum_{i=0}^{k}(-1)^{k-i}\binom{k}{i}\sum_{l=1}^{n}\sum_{r=l}^{n}s_r^{i}s_{l-1}^{k-i} \\ &= \sum_{i=0}^{k}(-1)^{k-i}\binom{k}{i}\sum_{r=1}^{n}\sum_{l=1}^{r}s_r^{i}s_{l-1}^{k-i} \\ &= \sum_{i=0}^{k}(-1)^{k-i}\binom{k}{i}\sum_{r=1}^{n}s_r^{i}\sum_{l=1}^{r}s_{l-1}^{k-i} \\ \end{align} \] 枚举 \(i,r\),而 \(\sum\limits_{l=1}^{r}s_{l-1}^{k-i}\) 可以预处理前缀和 \(O(1)\) 求。
时间复杂度 \(O(nk)\)。
CF2104G. Modulo 3
每个点至多有一条出边,意味着这个图由若干环和链组成。并且,这种特殊的结构使得同一个环上的点的颜色一定相同,而链上的每个点都能取 \(k\) 种颜色中的任意一种。
具体的,设图中环的数量为 \(c\),第 \(i\) 个环的长度为 \(l_i\),对于一个给定的 \(k\),答案是: \[ k^c\cdot k^{(n-\sum\limits_{i=1}^{c}l_i)}=k^{n+c-\sum\limits_{i=1}^{c}l_i} \] 根据欧拉定理,对于任意互质的 \(a,p\),有 \(a^{\varphi(p)}\equiv 1\pmod{p}\),进一步对于任意 \(x\) 有 \(a^x\equiv a^{x\bmod \varphi(p)}\pmod {p}\)。于是: \[ k^{n+c-\sum\limits_{i=1}^{c}l_i}\equiv k^{(n+c-\sum\limits_{i=1}^{c}l_i)\bmod 2}=k^{n\bmod 2+c\bmod 2+\sum\limits_{i=1}^{c}l_i\bmod 2}\pmod{3} \] 注:当 \(k\) 和 \(3\) 不互质时,\(k\) 为 \(3\) 的倍数,答案一定是 \(0\),可以特判掉。
令 \(M = c\bmod 2+\sum\limits_{i=1}^{c}l_i\bmod 2\),注意到奇环对 \(M\) 是没有任何贡献的,于是 \(M\) 等价于 "偶环个数\(\bmod 2\)"。
有向图偶环是不好维护的,但这题中只要有偶环就一定连通(指存在一个点,环上的所有点都能从该点到达),故实际上我们可以当作无向图偶环来处理,用一个并查集维护。
因为是动态图,所以还要套一个线段树分治。
时间复杂度 \(O(q\log^2 q)\)。
qoj7653. Balloon Darts
枚举一条直线都会用掉 \(O(n^2)\) 的复杂度,启发我们并不需要枚举所有 \(n\) 个点。
依据抽屉原理,\(k\) 条直线(这里 \(k=3\))上任取 \(k+1\) 个点,必然有两点满足确定的直线是 \(k\) 条中的一条。
或者反证法,如果选出的 \(k+1\) 个点不存在两点组成目标直线中的一条,则这 \(k+1\) 个点需要 \(k+1\) 条直线才能消除。
于是我们的做法是:
- 对于当前 \(k\),从前 \(k+1\) 个点里选两点构成一条直线,遍历所有剩下的点,消除在这条直线上的点。
- 将问题递归到 \(k-1\)。边界条件是点数 \(\le 2k\) 返回
true
。
时间复杂度 \(O(n)\)。
CF1437E. Make It Increasing
*2200 Code
trick:令 \(a_i\leftarrow a_i-i\),则最长上升子序列 \(\to\) 最长不下降子序列。
令 \(a_0=-\infty,a_{n+1}=+\infty\) 并将 \(0\) 和 \(n+1\) 加进 \(\{b\}\) 中,则整个数列被划分为若干可以修改的段。
每个段分开考虑,设当前段为 \([l,r]\),则需要修改的位置数量是 \((r-l+1)-cnt\),其中 \(cnt\) 是 \([l,r]\) 中值在 \([a_{l-1},a_{r+1}]\) 里的最长不下降子序列长度。
时间复杂度 \(O(n\log n)\)。
CF1440D. Graph Subset Problem
*2600 Code
将一个 \(k\) 个点的 clique 称作 \(k\)-clique,满足题意的子集称作 good-subset。
注意到一个点如果度数 \(<k-1\),那么它既不可能组成 \(k\)-clique,也不可能组成 good-subset,我们可以把这个点删掉。
当一个点被删掉时,它的邻居的度数就会 \(-1\),进而可能出现新的度数 \(<k-1\) 的点,所以我们是按照类似拓扑序的方式删点(当一个点度数 \(<k-1\) 时被加进队列)。
最终,图上所有点的度数都至少是 \(k-1\)(如果至少是 \(k\),那么所有点一定组成 good-subset,直接输出)。此时,要满足 \(\frac{n(k-1)}{2}\le m\),剩余点数 \(n\) 满足 \(n\le \frac{2m}{k-1}\)。
我们可以枚举每个度数为 \(k-1\) 的点作为 \(k\)-clique 的一部分,标记它和它的 \(k-1\) 个邻居,\(O(k^2\log k)\) 验证这个 \(k\)-clique 是否合法。(\(\log\) 是在邻接表中二分查找的复杂度,如果使用 unordered_map
或其它哈希方法则可以省去)
最多验证 \(n\) 个点,故复杂度 \(\le \frac{2m}{k-1}\cdot k^2\log k\approx O(mk\log k)\)。又由 \(\frac{k(k-1)}{2}\le m\),故 \(k\le \sqrt{2m}\),也就是 \(O(m\sqrt{m}\log m)\),可以接受。
若找到了一个 \(k\)-clique,就可以退出。否则,将这个点删掉。最终如果没有删光,仍旧得到一个点度数至少为 \(k\) 的图,一定是 good-subset。
注意到找 \(k\)-clique 的过程和一开始一样需要删点,删点后要跑拓扑,那么不如将一个点加进队列条件调整为度数 \(<k\),一遍拓扑一边验证当前点是否可能组成 \(k\)-clique。
写代码之前务必想清楚实现的细节,本题容易枚举不当导致复杂度退化。
时间复杂度 \(O(m\sqrt{m}\log m)\)。
CF1440E. Greedy Shopping
*2600 Code
操作一不会破坏序列的单调性,\(\{a\}\) 始终单调递减。
对于操作 1 x y
,我们可以二分出第一个 \(a_i< y\) 的下标 \(i\),转换为将区间 \([i,x]\) 修改为 \(y\)。
对于操作 2 x y
,一个直观的想法二分出 \(x\) 右侧第一个满足 \(\sum\limits_{i=x}^{p} a_i>y\) 的 \(p\),然后贡献就是区间 \([x,p-1]\) 的长度。但注意到并不是只有这一段区间有贡献,实际可以是 \(x\) 右侧的若干段区间。
可以证明,区间个数至多是 \(O(\log y)\) 级别的。我们用 \(1\) 表示选中的区间,\(0\) 表示未选中的区间,那么 \(x\) 右侧形如 \(101010\ldots\),左数第一个 \(0\) 的 \(\sum a_i\)(设为 \(A\))比左数第一个 \(1\) 的 \(\sum a_i\)(设为 \(B\))要小,那么这一组 \(10\) 存在就说明 \(y-A < B < A\to y<2A\to A>\frac{y}{2}\),即每次 \(y\) 都至少消费掉自身的一半,得证。
回到证明之前,当找到 \(p\) 后,累加贡献,\(y\) 减去区间 \([x,p - 1]\) 的和,就可以继续在 \(p\) 右侧二分出第一个 \(a_j\le y\) 的 \(j\),再在 \(j\) 右侧二分出第一个满足 \(\sum\limits_{i=j}^{p_2}a_i> y\) 的 \(p_2\),得到区间 \([j,p_2-1]\),以此类推...
操作一用线段树区间赋值,操作二在线段树上二分,可以少一个 \(\log\),共二分 \(O(\log y)\) 次。
时间复杂度 \(O((n+q)\log n +q\log n\log w)\),\(w\) 是值域。