1.4 分块

\({\Large 约定}\)

  1. 用集合符号表示位运算符号,用 $ \oplus $ 表示异或,特别的,$ i \in S$ 表示二进制数 \(S\) 的第 \(i\) 位为 \(1\)
  2. \(V\) 表示值域,\(\sum\) 表示字符集,\(\omega\) 表示 bitset 的常数 \((\omega = 64)\)
  3. 除去用 \(()/[]\) 表示开闭区间外,\([]\) 仅表示艾弗森约定,\(\{\}\) 仅表示集合,括号嵌套全用 \(()\)
  4. 字符串或序列角标为区间表示对应区间的子串

problems

\(\textcolor{white}{\mathrm{pw:hellloWorlds}}\)

P3396 哈希冲突

\(\textcolor{green}{\mathrm{普及+/提高}}\) tag 根号分治

感觉如果想到根号分治了应该就不难了?
显然当 \(p\) 较小的时候是可以直接存储答案处理掉的,当 \(p\) 较大的时候我们发现其实满足条件的数量也不会很多,所以就可以根号分治去做了。
当然我也不知道为啥设定了一个阈值 \(B\) 会出错。QAQ

submission

2025.12.25

P6177 【模板】树分块 / Count on a tree II

\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 分块 LCA

树分块模板题。
分成三步:

  1. 预处理 \(\operatorname{LCA}\)、深度、以及哪些点作为分界点。我们设置一个阈值 \(B\),当它到它子树中的分界点最远距离超过 \(B\) 时,说明这个点就是分界点了。当然我们要给这些点新的编号以节省空间。
  2. 用 bitset 处理出分界点之间的颜色状态。\(b_{x, y}(dep_x<dep_y)\) 表示 \(x\)\(y\) 的路径上颜色状态。这里的颜色状态不包括 \(x\)。维护一个栈,当 \(dfs\) 到一个分界点时,栈中的点一定是该节点的祖先,那我们也能比较快地维护 \(b_{x,y}\) 了。把这个点加入栈中并继续向下递归,遍历完子树后弹出。
  3. 计算答案,先求出 \(u\)\(v\)\(\operatorname{LCA}\),这里 \(\operatorname{LCA}\) 的贡献要最后单独去算。我们先让 \(u\)\(v\) 向上跳直到跳到一个分界点。然后再通过分界点往上跳,最后再从分界点跳到 \(\operatorname{LCA}\)。然后就可以计算答案了。

submission

2025.12.25

SP10707 COT2 - Count on a tree II

tag 分块 LCA

跟上面那题一模一样,只不过这题不用强制在线。(所以理论上树上莫队也行

submission

2025.12.25

P3384 【模板】重链剖分 / 树链剖分

\(\textcolor{blue}{\mathrm{提高+/省选−}}\) tag 树链剖分 线段树

找出每个结点的重儿子,找出每一条链,维护一个线段树,子树操作就去处理子树对应的那段 \(dfn\),路径操作就每次找链深度更大的那个点往上跳,最后再处理一下两个点之间的路径。
应该就这样了吧?

submission

2025.12.25

P1903 【模板】带修莫队 / [国家集训队] 数颜色 / 维护队列

\(\textcolor{blue}{\mathrm{提高+/省选−}}\) tag 莫队 分块

好像就是在普通莫队上略作修改?
考虑到现在有了修改操作,那我们可以给每一次修改操作定一个时间,给莫队再加一维。排序的话优先级就按照 \(l\) 的块、\(r\) 的块、询问的时间排序。对于时间的修改在 \(l\)\(r\) 的修改之后就行了。如果修改在区间范围外的话就先不修改了,但还是要修改原序列。

submission

2025.12.25

P3674 小清新人渣的本愿

\(\textcolor{blue}{\mathrm{提高+/省选−}}\) tag 莫队 分块 枚举 bitset

因为没有强制在线所以可以离线
先考虑每一种操作要怎么判断。乘法很简单,只需要 \(\mathcal{O(\sqrt N)}\) 去枚举一下因数,判断两个数是否都有即可。现在考虑减法,显然如果要找到 \(z-y=x\),那么有 \(y=z-x\),我们发现假如我们已经用 bitset 记录了每个数字是否存在,那么可以通过 bitset 的位运算来实现判断。假如说目前的存在状况为 \(s1\),我们可以将 \(s1\) 与左移 \(x\) 为后的 \(s1\) 进行与运算,看看是否有 \(1\)。加法同样,$z+y=x,z-(-y)=x,z-(N-x)=x-N,显然有 \(N-x=z-(N-x)\),我们再用一个 bitset 记录一下 \(N-x\),设为 \(s2\),然后让 \(s2\) 右移 \(N-x\) 位后与 \(s1\) 进行与操作,判断一下是否有 \(1\)。这个东西的修改看上去很可以莫队然后就做好了。

submission

2025.12.26

P5355 [Ynoi Easy Round 2017] 由乃的玉米田

\(\textcolor{blue}{\mathrm{提高+/省选−}}\) tag 莫队 分块 枚举 bitset

上面那道题的加强版。
现在加了除法。假如说 \(x>\sqrt N\),那么满足整除条件的对数不会超过 \(\lfloor\frac{N}{x}\rfloor\leq\sqrt N\) 个,那么这个显然可以在莫队的时候一起做掉。
假如说 \(x\leq\sqrt N\),那么我们可以把这部分操作移到莫队之外去做。先枚举 \(x\),再枚举 \(i\),维护两个东西:\(lst_i\) 表示这个数最近一次出现的下标,\(mx_i\) 表示右端点为这个点时左端点最大是多少。显然假如说当前这一位为 \(a_i\),那么我们可以用 \(lst_{a_i\times x}\)\(lst_{\frac{a_i}{x}} (x\vert a_i)\) 去转移,取最大的左端点即可。求答案就找到对应的位置就好了。

submission

2025.12.26

P5309 [Ynoi2011] 初始化

\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 分块 枚举 根号分治

感受到了 Ynoi 的震撼。
之前有想过类似的题目。考虑根号分治,显然假如说 $x\geq\sqrt n $ 的话,说明修改的个数是 \(\leq n\) 的,可以直接用分块修改。如果说 \(x>\sqrt n\) 的话,我们可以记录一下循环周期为 \(x\) 时,周期中第 \(y\) 个位置的修改结果,总共有不超过 \(\mathcal{O(n)}\) 种不同的情况。求答案时先计算分块中这段区间的和,再枚举周期把这些单独的贡献加上去。我们要前缀和与处理一下每个周期否则时间复杂度会有点爆炸,然后就做完了。
非常非常重要的一点,这道题目卡常。可以通过减少取模(有些时候用 longlong 可以减少操作次数)、在该开 longlong 的时候开 longlong、fread 等神秘技巧卡过去。\(500ms\) 刚好卡过去(看来我的实现还是太差了点/kk)。

submission

2025.12.26

P14420 [JOISC 2014] 历史的研究 / Historical Research

\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 分块 莫队

回滚莫队板子题。
考虑怎么莫队。我们发现在扩大区间的时候新增的贡献是好计算的,但是在缩小区间的时候对贡献的撤销比较难。这时候就需要回滚莫队了。我们按照普通莫队的想法先把序列分成若干块,显然左右端点在同一个区间的询问是可以直接做掉的。现在考虑不在一个区间的做法。显然可以在排序的时候把左端点在同一个区间的询问按照右端点从小到大排序,把左端点所在块的右边界后面的贡献逐个增加,这样扩展右端点的复杂度是 \(\mathcal{O(n)}\) 的。我们发现左端点都是在一个块内的,显然新增一个左端点的贡献是 \(\mathcal{O(n)}\) 的,是可以接受,那么就把答案分成了两部分相加。
复杂度还是 \(\mathcal{O(n\sqrt n)}\) 的。

submission

2026.01.04

P13984 数列分块入门 9

\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag 分块 莫队

同样是回滚莫队板子题。
回滚莫队具体的流程可以看上面的,这里只需要把贡献改成最小的众数即可。
在处理左端点的时候一定一定不要忘记在求答案的时候先加上。

submission

2026.01.04

SP10707 COT2 - Count on a tree II

tag 分块 LCA

(没错还是这道题)
这次考虑一种树上莫队的做法。
如果说让指针在树上移动,这显然不太好处理,有点无序 (或者说我太菜了)
考虑到可以把树拍成序列去做,所以需要找出一种优秀的序列。有欧拉序和括号序两种选择,我使用的是括号序。
括号序,顾名思义,就是记录遍历到一个结点和遍历完这个结点的子树的时间戳。这样的话这两个时间点是两两对应的。我们用 \(L_u\)\(R_u\) 分别表示遍历到 \(u\) 和遍历完 \(u\) 的子树的时间点,用 \(d_i\) 记录下第 \(i\) 个时间点对应的点,这样就得到了一个长度为 \(2n\) 的序列,只需要在这个序列上面跑莫队即可。在这个区间中,只有包含 \(1\) 次的结点才能够产生贡献。
如何找到对应路径在 \(d\) 数组上的区间?假设 \(L_x < L_y\)\(x\) 不是 \(y\) 的祖先,那么我们只需要求 \([R_x,L_y]\) 即可,如果 \(x\)\(y\) 的祖先,那求 \([L_x,L_y]\) 即可。当然还要特判一下 \(\operatorname{LCA}\) 的情况。
\(x,y\)\(\operatorname{LCA}\)\(lc\),那么 \(lc\) 子树外的点不会包含在这个区间中,出现次数是 \(0\)。如果是在路径外的点,那么显然它的子树会在区间中出现 \(0\)\(2\) 次,也不会产生贡献。在路径上的点,从 \(x\)\(y\)\(lc\) 的路径上(不包含 \(lc\)),这些点的 \(L_i<L_{x,y}\)\(R_i>R_{x,y}\)。所以都会出现一次,那么再特判一下 \(lc\) 就好了。
记住,树上莫队拍平后的 结点数是 \(2n\),求属于哪个块和块的大小都要 开成 \(2n\)!!!

submission

2026.01.07

P4074 [WC2013] 糖果公园

\(\textcolor{purple}{\mathrm{省选/NOI−}}\) tag LCA 莫队

带修的树上莫队。
显然原理就相当于树上莫队+带修莫队,只需要在原来的基础上加上一个时间维度即可。
考虑对于时间上的修改要怎么进行,类似带修莫队的想法,假设当前修改的时间是 \(i\)\(dx_i\) 表示当前修改的点,\(dy_i\) 表示当前修改的颜色,现在询问的区间是 \([l,r]\),那么对于 \(L[dx_i]\in [l,r]\)\(R[dx_i]\in [l,r]\) 的情况都修改一下这个点,相当于删除这个点的贡献。交换一下 \(dx_i\)\(dy_i\) 的颜色,再重复一次这个操作,相当于加上这个点的贡献。特判一下 \(\operatorname{LCA}\) 的情况再算一下答案即可。

submission

posted @ 2025-12-25 09:08  yqfff_qwq  阅读(7)  评论(0)    收藏  举报