莫队对不对?
前言
如果你想熟练掌握莫队,这篇文章一定不适合你。
恶补莫队,因为时间紧任务重所以不会有什么讲解,这篇博客只是作为笔者以后复习莫队用的东西,对他人可能没有过多实际意义。这篇文章的讲解很粗糙,而且不会放太多太难的题,望谅解。
理解
莫队相当于是一种特殊的扫描线,它能同时去掉一个维度上的两个 side,但是要花费 \(O(\sqrt n)\) 的时间。
有的信息不太好用静态的 ds 去维护的时候可以考虑莫队。我认为发明莫队这个算法其实就是为了更好的平衡维护信息与查询信息的过程,像一些不好合并差分的信息我们可以用一种看似暴力的方式处理。
普通莫队
将询问排序,注意我们排序将询问的左端点分块,右端点按奇偶决定正序倒序。
维护两个指针 \(l,r\),每次暴力移动指针,顺便更新每个位置带来的新的贡献。注意先加后减,防止维护的信息出现一些神秘错误。
注意块长取 \([400,700]\),个人习惯 \(sn=450/666\)。
时间复杂度 \(O(n\sqrt n\times k)\),其中 \(k\) 代表更新每个位置的信息的复杂度。
带修莫队
我们手动升维,将时间当做第三维信息,让每次修改后时间维度增加。有点像不同的版本之类的(?)
对于时间变化的更新方式有些特别。注意我们需要判断改变的位置是否在当前维护的位置内,如果在就需要删除原来的换成新的。最后交换修改前后的值,修改的信息要单独用结构体存一下,因为随着“版本”的更新,修改的信息可能是“回溯”到之前的信息。
这种莫队的块长有些不同,个人习惯取 \(sn=6000/6666\)。
时间复杂度 \(O(n^{5\over3}\times k)\),话说如果 \(k\) 再带一个 \(\log\) 那不炸了吗。
树上莫队
其实很简单,你考虑怎么会好做一点?是不是把树拍平变成序列?说干就干,我们直接启动欧拉序,然后查树上的路径 \((u,v)\) 就变成查区间 \([lp_u,lp_v](lp_u<lp_v)\)。考虑一个位置如果在区间中出现了一次说明需要被考虑贡献,否则就不用考虑。于是我们对每个位置记录一个 rev=0/1 表示是否需要考虑贡献,每扫到这个位置一次就将其 rev^1。注意还有 corner,考虑如果 lca=u 的情况,我们的区间里面会有两个 u 导致 u 的信息没有被算进答案,所以我们遇到这种情况就查询区间 \([rp_u,lp_v]\)。对于普通情况其实我们并没有算到 u 和 v 的 lca,所以我们对每个普通的询问记一下 lca 然后单独插入即可,但是统计完答案记得要删除,因为这个位置不一定与查询区间连续。
块长实测取 \(sn=3000\) 非常优秀,带修取 \(sn=6000\)。
时间复杂度 \(O(\text{能过})\)。
回滚莫队
有点意思。
想那些维护最远距离之类的东西,你删除很麻烦,就需要它。
具体实现过程中排序不需要奇偶分类,对于左端点在同一个块的询问右端点一定单调不降,于是用一个指针扫掉。
一个块内的暴力算答案。不在一个块的就每次暴力扫左边,然后合并右边的信息。注意每次左端点所在的块改变之后维护的信息全部要清空,因为上一个块的现在用不着了。
块长取法与普通莫队相同即可,时间复杂度也一样。
bitset莫队
遇到需要处理值域有关的信息可以考虑莫队套上 bitset,实在是非常优美!只能说是赏心悦目的暴力美学!
其实就是在普通莫队上装上 bitset,换句话说是用位运算结合 bitset 快速更新查询信息。
块长取法与普通莫队相同即可,时间复杂度也一样,但是真的很优美!
二离莫队
这是一个神奇的东西。
我最开始准备在这段时间搞莫队的知识以及重点写一下二离莫队都是因为一次巧合。SCTT 的 Day3T1 居然出了一道板子题?!关键是我不知道有二离莫队这么一个东西然后就只会 \(O(n\sqrt n\log n)\) 喜提 50pts 的好成绩,甚至我赛时还以为有什么不用莫队的做法导致小破防了一天。在一番斟酌下我决定补一补莫队分块的题,因为我感觉自己对这些内容运用不是很熟练。
废话不多说,首先我们需要知道什么时候应该用二离莫队?当我们遇到普通莫队的复杂度为 \(O(n\sqrt n\times k)\) 然后带 k 就会炸并且信息可差分的时候就需要二离莫队。这个东西可以把 k 这个系数提到外面去,从而变成 \(O(n\sqrt n+nk)\) 的优秀复杂度。现在考虑做法。
我们每次需要查一个形如 \(f(l,r,g(r))\) 的函数,若 f 可差分我们就改写成 \(f(1,r,g(r))-f(1,l-1,g(r))\) 的样子。对于前面一项我们是可以做到普通莫队快速处理的,考虑后面一项。其实我们可以用一个扫描线去扫所有的 \(l-1\),只需要我们在莫队的时候将每个 \(l-1\) 对应的这些 \(g(r)\) 用 vector 存一下即可。
其实二离莫队的本质是在差贡献,将信息进行分类,然后用不同的手段处理。对于第二项的信息不好直接算所以我们对其离线处理,这就是一个二次离线的过程。
后记
后续可能会自己组一个题单,但大概率会引用 dx 的题单,因为这个题单比较全面详细,里面的题大部分都建议去写。题单放在这里。