🍕🏠🌋 当前时间是:

 

块状数据结构选做

收集了最近做的一些块状数据结构题,涉及分块,莫队,块状链表等,难度大多不是很高,老少皆宜。 QAQ

P4168 [Violet]蒲公英

题目链接

大意:静态在线区间众数

先离散化,预处理出 \(cnt_{i,j}\) 和 \(mode_{i,j}\),分别表示前 \(i\) 块中数值 \(j\) 出现的次数和第 \(i\) 到第 \(j\) 块的众数。可以 \(\mathcal{O}(n\sqrt{n})\) 实现(\(mode_{i,j+1}\) 可由 \(mode_{i,j}\)\(\mathcal{O}(\sqrt{n})\) 的时间内推出)。

对于每次查询,答案要么在散块,要么在整块。只需扫描散块的所有数,判断其是否可以更新答案即可。

时间复杂度 \(\mathcal{O}((n+m)\sqrt{n})\)

参考代码链接

P4135 作诗

题目链接

大意:静态在线区间出现正偶数次的数值的个数

先分享一个我的奇怪做法,

显然,\(出现正偶数次的数值的个数 = 区间数值个数 - 出现奇数次数值的个数\)

区间数值个数主席树很好做,我们考虑如何处理出现奇数次数值的个数,

\(cnt_i\) 表示 \(i\) 出现的次数,如果暴力计算,每逢一个数 \(v\),就让 \(cnt_v\) 加一,那么只要统计 \(cnt\) 中的奇数的值的数量即可,

我们让 \(cnt_i\) 的值模 2,可以发现,加一就相当于 \(cnt_v=cnt_v ~\texttt{xor}~1\)

于是思路就很明显了,对序列分块,设块长为 \(T\),预处理 \(\mathcal{O}(\dfrac{n}{T})\)\(\texttt{bitset}\) 对于第 \(i\)\(\texttt{bitset}~cnt_i\),存储第 1 到第 \(i\) 块末尾这些数按上面的方式做出的结果 (即 \(cnt_{i,j}\) 表示前 \(i\) 块中数值 \(j\) 出现次数的奇偶性),这个东西是前缀可减的(\(cnt_{p,j}~\texttt{xor}~cnt_{q,j}\) 表示第 \(p\) 到 第 \(q\) 块数值 \(j\) 出现次数的奇偶性),加上散块暴力,单次询问复杂度为 \(\mathcal{O}(\dfrac{n}{w}+T+\log n)\) (假设 \(n\) 与值域同阶, \(\log\) 为主席树复杂度)。

对于预处理,每个块分别预处理,然后做一个前缀 \(\texttt{bitset}\) 异或即可,预处理时间复杂度 \(\mathcal{O}(\dfrac{n^2}{Tw})\)

总的时间复杂度就是 \(\mathcal{O}(\dfrac{n^2}{Tw}+m(\dfrac{n}{w}+T+\log n))\),由均值不等式,取 \(T=\dfrac{n}{\sqrt{mw}}\) 即可取到理论最优复杂度。(实际调块长很玄学QAQ)

可通过本题,但是我的写法跑的不快awa

参考代码链接

下面分享一下正宗 \(\mathcal{O}(n\sqrt{n})\) 做法

预处理出数组 \(s_{i,j}\),表示第 \(i\) 到第 \(j\) 块这些整块的答案,可以 \(\mathcal{O}(n\sqrt{n})\) 实现。

对于每组询问,扫描散块的数,计算对答案的影响即可,实现的时候有些细节要注意。

参考代码链接

P4396 [AHOI2013]作业

题目链接

题目大意:静态询问区间值在 [a,b] 内的数的个数和数值的个数

考虑莫队,指针总共移动 \(\mathcal{O}(n\sqrt{m})\) 次,查询答案 \(\mathcal{O}(m)\) 次,因此我们需要一个 \(\mathcal{O}(1)\) 修改,\(\mathcal{O}(\sqrt{n})\) 查询的数据结构。我们只需要对值域分块即可,维护每个块内数值的个数和数的个数,查询的时候散块暴力查询,整块直接加上标记就可以了。

时间复杂度 \(\mathcal{O}(n\sqrt{m}+m\sqrt{n})\)。调一下块长跑得飞快。

参考代码链接

P9410 『STA - R2』机场修建

题目链接

大意:要求数据结构支持联通块合并、编号在区间 [a,b] 内的点点权加、查询联通块点权和

维护数组 \(cnt_{i,j}\) 记录并查集代表元为 \(i\) 的联通块在第 \(j\) 块的个数。每个并查集再维护一个 \(sum\),表示散块暴力加上的点权。

对于区间加,整块打上 tag,散块暴力加到对应并查集的 \(sum\) 上。

合并直接做即可。

对于查询代表元为 \(t\) 的并查集,第 \(i\) 个整块的贡献就是 \(tag_i \times cnt_{t,i}\)\(\mathcal{O}(\sqrt{n})\)计算即可,最后加上 \(sum_t\)

时间复杂度 \(\mathcal{O}(n\sqrt{n})\),空间复杂度 \(\mathcal{O}(n\sqrt{n})\)

这道题空间限制比较紧,但是卡一卡就能过去(也可以把 \(cnt\) 搞成 \(\texttt{vector}\),进而空间复杂度线性,但是我的写法时间复杂度要带个二分的 \(\log\)

参考代码链接

动态数组版

update 2024/8/25 :

莫队二次离线 P4887

链接

大意:区间异或后二进制下有 \(k\)\(\text{1}\) 的数对个数。值域 1.6e4

称两数能匹配当且仅当它们的异或和二进制下有 \(k\)\(\text{1}\)

直接莫队可以 \(O(\dbinom{14}{k})\) 转移,但不能接受。

考虑拆转移的贡献,以 \(L\) 端点左移到 \(L-1\) 为例:

\(a_{L-1}\) 的贡献为 \([L,R]\) 内和 \(a_{L-1}\) 匹配的数的个数。

可以拆成 \([1,L-1]\)\([1,R]\) 两个区间。

于是可以发现,定义位置 \(x\) 的权值为 \(a_x\)\([1,x-1]\) 内能匹配的数的个数,就可以实现 \(O(1)\) 第一部分转移。

还可以发现,对于一个询问,第二部分贡献的形式是 \([QL,L-1]\) 中的数在 \([1,R]\) 内能匹配的数的个数。(其中 \(QL\) 是本次询问的左端点,\(L\) 是当前莫队指针的左端点)

按照 \(R\) 离线,由于 \(\sum O(L-QL)=O(n\sqrt{n})\),可以暴力统计贡献。(此处认为询问和序列长度同级)

按排序后的询问顺序把第二部分贡献前缀和回去就好了。

可以发现,这个套路实质上就是对于高复杂度但具有可减性的转移拆成 \(O(1)\) 的转移和离线后总长度为 \(n\sqrt{n}\) 的区间询问。

代码见洛谷记录。

还没有写完qwq

posted @ 2023-06-17 08:27  zzafanti  阅读(37)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end