浅谈莫队的小细节
关于莫队
提起莫队,想必是很多人十分钟爱的暴力算法,毕竟在可以离线的部分区间询问问题当中,只需要花十分钟写一份简单的暴力,就可以获得
但是在学习简单的莫队的过程中,我也有一些问题以及自己的思考,写在这里分享给大家,希望对热爱或不热爱莫队的你都有帮助。
关于 l,r 的初始值
相信初学莫队,大家都对于
在这里,我的理解是这样的(欢迎打脸)。
我们先来看莫队过程的代码,我的写法大体长这个样子:
int l = 1,r = 0;
for(int i = 1;i <= m;i++)
{
int ll = q[i].l;
int rr = q[i].r;
while(l < ll) del(a[l]),l++;
while(l > ll) l--,add(a[l]);
while(r < rr) r++,add(a[r]);
while(r > rr) del(a[r]),r--;
ans[q[i].id] = sum;
}
我们考虑从初始状态需要依次将
while(l < ll) del(a[l]),l++;
while(r < rr) r++,add(a[r]);
我们注意观察
而如果
当然,查询区间端点为
因此,我们要将莫队初始化为
关于一些贡献的计算
接下来的问题,并不一定只在莫队中适用,只是恰好最近多次遇到了这个问题,就写在这里,也算是自己一点见解。
先来看个例题。
P4462 [CQOI2018] 异或序列
这道题目,首先一个显然的 trick 是,异或操作是可以类似前缀和去求的,那么我们也就是需要求出区间中有多少对
我们考虑如何在移动的过程中加入和删除贡献,不难发现,只要我们将一个数对
如果还是不太明白,我们以删除操作为例,详细讲解一下。
如果此时我们扫描到了一个数
将
对于已经被删除的,在删除
所以在做查询数对的题目时,我们就不需要考虑莫队插入和删除的顺序,只需要在插入或删除一个数字的时候,在目前的序列中查询并记录贡献即可,这样可以保证贡献被记录在后加入或删除的元素上,不重不漏。
下面还有一道比较难的题目,也是希望大家知道前面统计贡献方法,嫌麻烦的朋友可以直接跳过。
P12480 [集训队互测 2024] Classical Counting Problem
这道题目只听了做法,还没有写代码。
具体做法大家可以参考 这位大神的题解。
最后统计部分,我们需要扫描线扫描
我们考虑将贡献统计在
这部分主要介绍的是统计数对贡献的一种思路,希望对大家有所帮助。