莫队

当我们在处理多个区间的询问,且询问可以离线时,我们可以考虑使用莫队。

莫队的思想非常巧妙,也非常好理解。

首先,如果按照常规做法,对于每一个查询 \([l,r]\) 我们都需要移动左右指针,不难发现复杂度最坏是 \(O(mn)\) 的。

然后,我们想,如果把左端点作为第一关键字,右端点作为第二关键字,进行排序,那我们左指针移动就会减少很多了。但是我们发现,右指针还是需要大幅度的移动,最坏情况下复杂度依然是 \(O(mn)\)

而莫队,则是提出了一种巧妙的排序方式,它先把长度为 \(n\) 的序列分成 \(\sqrt n\) 个部分,每个部分长度是 \(\sqrt n\)。其先把 \(\lfloor \frac{x}{\sqrt n} \rfloor\) 作为第一关键字,然后把 \(r\) 作为第二关键字排序。

总之,这样处理了以后,时间复杂度降到了 \(O(n\sqrt n)\),证明可以感性理解一下,不在此处赘述。

有一个显然的优化:当 \(l\) 从一个块移动到下一个块时,\(r\) 大部分情况下都要从最右侧跑到最左侧,然后再往右跑,有点浪费时间,所以我们在第一关键字的奇偶性不同的情况下,第二关键字的排序策略要相反,这被称作“奇偶性优化”。

基本的模板如下:

l=1,r=0;
for(int i=1;i<=q;i++){
	while(l>b[i].l) l--,add(a[l]);
	while(r<b[i].r) r++,add(a[r]);
	while(l<b[i].l) del(a[l]),l++;
	while(r>b[i].r) del(a[r]),r--;
}

posted @ 2026-07-20 15:44  MistyPost  阅读(4)  评论(0)    收藏  举报