莫队

莫队

假设 n,m 同阶,对于序列上的区间询问问题,如果得知 [l,r] 的答案,可以在 O(1) 的时间推算出 [l1,r],[l+1,r],[l,r1],[l,r+1] 的答案,那么我们就可以在 O(nn) 的时间求出所有询问的答案。

普通莫队

将所有的询问离线后以左端点所在的块为第一关键字,右端点为第二关键字进行排序。按排序后的顺序处理每一个询问,暴力从上一个区间的答案推出当前区间的答案。

注意移动指针时应先扩大区间, 后缩小区间,时间复杂度 O(nn)

优化:

  • 调整块长。
  • 奇偶性排序:在选择奇数块时,按照右端点从小到大排序,在偶数块时从大到小排序,这样可以减少右端点进行大跳动的次数,常数优化为原来的一半。
    • 原理:因为右指针移动到右边后就不需要跳回左边了,而跳回左边后处理下一个块是要跳动到右边的。

P1494 [国家集训队] 小 Z 的袜子

给定 a1nm 次询问区间内任选两个数相同的概率。

n,m5×104

将题意用式子可以表示为:

cntk(cntk1)2len(len1)2=cntk2cntklen(len1)=cntk2lenlen(len1)

问题就转化为求区间数字出现次数平方和。

考虑答案的增量:

(a+1)2=a2+2a+1

于是就可以很轻松地设计 add 函数和 del 函数了。

CF617E XOR and Favorite Number

给定 km 次询问区间内有多少子段异或和为 k

n,m105k,ai106

可以先预处理出前缀异或值,由前缀和性质可知,问题转化为有多少对 i,j 满足 sisj=k 。注意到 xy=k 等价于 xk=y 。于是问题转化为区间数字出现次数。

带修莫队

强行加上一维时间维,表示该操作的时间。在查询时修改,改多了就还原回来,改少了就改过去。

待修莫队的排序通常是这么排:

n 为序列长度,m 个询问, t 个修改,则最佳块长为 n2tm3 ,实际操作取块长为 n23 即可。当 n,m,t 同数量级时时间复杂度为 O(n53)

P1903 [国家集训队] 数颜色 / 维护队列

给出序列 a1nm 次操作,操作有:

  • Q l r :求 alr 中颜色总数。
  • R p c :将 ap 改为颜色 c

n,m133333

注意一下修改操作 (x,k) 的影响,当且仅当 x[l,r] 才要统计。

考虑如何撤销操作,每次直接交换 axk ,这样下次修改就相当于撤销了。

树上莫队

通常用于处理树上路径信息统计问题,考虑将树的括号序跑下来,在括号序上跑莫队。

设点 i 入栈时时间戳为 sti ,出栈时时间戳为 edi ,则对于查询 uv 路径上的信息分类讨论(钦定 dfnu<dfnv ):

  • uv 的祖先:查询 [stu,stv] 即可。
  • u 不是 v 的祖先:查询 [edu,stv]LCA(u,v) 即可。

注意查询时应忽略出现两次的点,括号序要开两倍内存。

时间复杂度和普通莫队是一样的。

SP10707 COT2 - Count on a tree II

给定一棵 n 个点的树,m 次查询 uv 路径上节点颜色种数。

n4×104,m105

模板,下给出参考代码。

P4074 [WC2013] 糖果公园

给定一棵树,q 次询问 uv 路径上 acij=1cntciwi 的值,其中 aci 表示颜色 ci 的价值,cntci 表示 ci 出现次数,wi 表示出现 i 次的价值。

n,m,q105

树上带修莫队模板,下给出参考代码。

回滚莫队

大前提:一类可离线问题。

  • 有些信息区间伸长时很好维护,区间缩短时却不好维护。
  • 有些信息区间缩短时很好维护,区间伸长时却不好维护。

实现

只增不删回滚莫队

首先将询问排序,应保证左端点在同一块内的询问的右端点单调不降。

若区间端点在同一块内,直接暴力解决即可。

否则每次处理询问时,令 l 指针指向块尾,r 指针指向块尾。先移动 r 指针,由于右端点不降,于是只要插入即可。保留下来信息,后移动 l 指针求解,处理完后用前面保留下来的信息恢复即可。

只删不增回滚莫队

首先将询问排序,应保证左端点在同一块内的询问的右端点单调不升。

若区间端点在同一块内,直接暴力解决即可。

否则每次处理询问时,令 l 指针指向块头,r 指针指向 n 。先移动 r 指针,由于右端点不升,于是只要删除即可。保留下来信息,后移动 l 指针求解,处理完后用前面保留下来的信息恢复即可。

时间复杂度分析

设分块大小为 B ,则时间复杂度为 O(mB+n2B) ,当 B=nm 时复杂度最优为 O(nm)

应用

JOISC2014 歴史の研究

m 次询问区间内 maxai×cntai

n,m105

模板题,下给出参考代码。

P5906 【模板】回滚莫队&不删除莫队

m 次询问区间中相同的数的最大出现下标差。

n,m2×105

模板题,下给出参考代码。

二维莫队

每个状态有四个方向可以扩展,每次移动指针要操作一行或者一列的数,具体实现方式与普通的一维莫队类似。

取块长 B=n×q0.25 ,总时间复杂度为 O(n2×q0.75)

P1527 [国家集训队] 矩阵乘法

q 次询问 n×n 矩阵中一个子矩阵的第 k 小数。

n500,q60000

先离散化,用莫队维护出矩形中出现的数,再值域分块即可。

这题好像二维莫队过不去,只有 60 分。

莫队二次离线

适用范围:

  • 可以莫队。
  • 一个数对答案的贡献与区间中别的数有关,移动端点的更新时间不是 O(1)

考虑把莫队移动的这些端点也都离线下来预处理,从而进一步优化。

因为莫队时一次离线,最后处理时又一次离线,故称为莫队二次离线。

假设更新答案的时间复杂度为 O(k) ,则使用二次离线莫队可以将时间复杂度从 O(nkn) 降到 O(nk+nn)

实现

考虑端点移动对答案的影响,以 [l,r][l,r+k] 为例,设 x 对区间 [l,r] 的贡献为 f(x,[l,r]) ,则考虑求 x[r+1,r+k]f(x,[l,x1]) 的值。可以差分:

f(x,[l,x1])=f(x,[1,x1])f(x,[1,l1])

对于 f(x,[1,x1]) 可以预处理得出,对于 f(x,[1,l1]) 可以在每个 l1 的位置记录一下需要计算哪些数的贡献,打标记的时候可以只标记左右端点,最后一起处理。

注意最后处理时须保证查询复杂度为 O(1) ,时间复杂度才是 O(nk+nn)

应用

P4887 【模板】莫队二次离线(第十四分块(前体))

m 次查询,每次给出 l,r,k ,求满足 li<jr,popcount(aiaj)=k 的二元组 (i,j) 的个数。

n,m105

模板,下给出参考代码。

[Ynoi2019 模拟赛] Yuno loves sqrt technology II

给你一个长为 n 的序列 am 次询问区间的逆序对数。

n105

首先直接莫队是 O(nnlogn) 的,然后二次离线就可以做到 O(nn+nlogn) 了。

P5501 [LnOI2019] 来者不拒,去者不追

m 次询问区间内所有数的价值和,一个数的价值定义为它在区间内的排名乘本身。

n,m5×105,ai105

考虑加入 x 这个数的贡献:

  • 对于所有大于 x 的数 y ,贡献全部增加了 y
  • 对于 x 本身,贡献就是 x×tt[l,r] 中比 x 小的数加 1

于是莫队二次离线时维护大于 x 的数的总和和小于 x 的数的数量即可。

莫队配合 bitset

P4688 [Ynoi2016] 掉进兔子洞

m 次询问,每次询问三个区间,把三个区间中同时出现的数一个个删掉,求最后三个区间剩下的数的个数和,询问独立。

n,m105,ai109

答案为 i=13(rili+1)3×k,其中 k 为三段区间内共有的数的个数,问题转化为求 k

考虑用莫队维护查询的区间内每个数的个数。对于一次询问,我们将其拆成传统莫队的三个询问:(l1,r1),(l2,r2),(l3,r3) ,分别进行处理。我们要得到 k,需要得到这三个询问中有哪些数、分别几个,然后取它们的交集即可。

注意一个数可能重复出现多次。我们考虑先将初始 a 数组进行离散化,只记录 a 数组每一个值对应排序好的数组的编号即可。这样,若干个相同的数便会留出若干个空着的编号,它们代表同一个值。然后使用这个离散化的对应关系用 bitset 存即可。

但是 105 的范围 bitset 存不下,可以把输入的查询分为若干组,每组 2×104 个数,对于每一组分别进行处理即可。

P5355 [Ynoi2017] 由乃的玉米田

m 次询问,每次询问区间内是否能找出两个数使得它们的差/和/积/商为 x

n,m,ai105

加减维护一个 bitset 就好了,单次询问复杂度为 O(nω)

积直接暴力枚举因数,单次询问复杂度为 O(n)

对于商,分类讨论:

  • 如果 xn ,那么可以暴力枚举商,然后判断有没有出现即可。因为这个商 n ,所以复杂度是正确的。
  • 如果 x<n ,可以预处理出 x[1,n) 的答案。对于每个 x 遍历一遍序列,找出每个 1in 的离 i 最近且 itpi ,满足 aiatpi 的商为 x ,于是每个询问的答案为 ltpr 。这一部分的时间复杂度为 O(nn)

总时间复杂度为 O(n2ω+nn)

P5313 [Ynoi2011] WBLT

m 次询问区间内元素组成最长的首项 <b 公差为 bb 每次询问给出)的等差数列的长度。

n,m,ai105

b>B 时,用莫队提取出一段区间中代表数字出现情况的 bitset ,然后把这个大 bitset0 开始分裂成一些长度为 b 的小 bitset 。显然,如果将分裂出来的这些 bitset 全部与起来,第一次全为 0 时的小 bitset 的下标即为本次询问的答案。

bB 时,考虑对每个 b 的剩余类分别处理,原问题可转化为在长为 nB 的序列上,询问 qB 次区间 mex 。线段树上二分可以做到 O(nBlogn)

posted @   wshcl  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示