题解 P9986【[Ynoi2079] r2pspc】
来个正解复杂度。
题意
给你一个长为 $n$ 的序列,$q$ 次询问给出区间 $[l,r]$,求 $\text{popcount}\left(\displaystyle\sum_{i=l}^r2^{a_i}\right)$。
$n\le 10^5$,$q\le 10^6$。
思路
值域可以离散化到 $O(n)$。
考虑暴力,注意到单次操作暴力进位是有均摊分析的,时间复杂度为 $O(n)$。
那么我们考虑回滚莫队,假设左端点现在处于一块内,块右边的部分直接暴力进位基于势能分析复杂度是正确的,问题是块内要撤销,不能使用基于均摊的暴力。
考虑值域分块,以每个块内出现过的数作为一个块的块尾。比如说块内有 $2,4,5$,那值域就被分为 $[1,2],[3,4],[5,5],[6,n]$ 几段。那么此时左端点移动带来的更新就只会在块尾进行。
考虑上一块尾对这一块首的进位,设这一块为 $[l_i,r_i]$,可以发现这部分进位对 $l_i+\log n$ 影响最多为 $1$。块长小于 $\log n$ 平凡,以下不讨论。我们考虑将每个块的前 $\log n$ 位压进一个 int 中存,记为 $low_i$。对于每个块记录其向下一块进位的次数(移动右端点时如果块尾需要进位也记录在此),但不实际进行。撤销时(注意到只会发生在块尾)如果这一位为 $0$ 直接在这一块的进位数里面减一即可。由于可能进的一位,我们还需要维护每个块中最大的 $p_i$ 满足 $[l_i+\log n,p_i]$ 均为 $1$。
动态维护每块除前 $\log n$ 位的 $1$ 的个数。查询时从小到大逐块处理,假设上一块进位了 $s$,将 $s+low_i$ 的前 $\log n$ 位的 $\text{popcount}$ 加入答案,如果 $s+low_i$ 右移 $\log n$ 位后仍非零,那么 $[l_i+\log n,p_i]$ 会变为 $0$,$p_i+1$ 会变为 $1$。
设序列块长为 $B$,移动左端点复杂度 $O(1)$,每一块移动右端点复杂度总和 $O(n)$,单次查询复杂度 $O(B)$。总时间复杂度 $O(qB+\dfrac{n^2}B)$,取 $B=\dfrac{n}{\sqrt q}$,时间复杂度 $O(n\sqrt q+q\log q)$。

浙公网安备 33010602011771号