【算法】莫队
一、概念
莫队是一种应用于离线询问的优美暴力算法。它是主要思想是让区间的左端点和右端点移动的距离加起来最短。
二、实现
假设现在有这样一串序列:,我们现在要求询问区间内的 的出现次数。
如果我们现在已经统计到了区间 ,现在询问 。
现在的答案是这样的:
我们发现现在的左端点 在询问的左端点的右边,所以我们将当前左端点向左移一位。现在维护的区间 有两个 了。
我们又发现现在的右端点 在询问的右端点左边,所以我们将当前右端点向右移一位。现在维护的区间 还是有两个 。
这时候的右端点还是在询问的右端点。所以我们再将右端点向右移一位。现在维护的区间 有三个 了。
这时候访问到的区间与询问的区间完全一样,我们就可以存储答案了。
这就是莫队的思想了(。你会发现这十分的像暴力,的确如此。但是为了保证时间复杂度,我们要引入分块的思想。先将 按照所在块的编号排序,在每个块中,再按 的大小排序。
这样的话我们发现在每个块中, 最多会移 次,每换一次块,就可能多移 次。同时,每次询问 都可能移动 次。所以时间复杂度应该为 。
我们发现每换一次块, 可能会从最右边跑到最左边,这显然不优。所以我们考虑奇偶性优化,如果第一个块的编号为偶数,那么块的编号为偶数就将 升序排序,为奇数就将 降序排序。如果第一个块的编号为奇数,那么就都反过来。
三、代码
感觉比较板的题是这题:小B的询问
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+5;
int n,m,k;
int a[N];
int buc[N];
int ansi[N];
int T;
int sum;
struct node{
int l,r,id;
}q[N];
bool cmp(node x,node y){
if(x.l/T==y.l/T) return x.r<y.r;
return x.l<y.l;
}
void add(int x){
sum-=buc[a[x]]*buc[a[x]];
buc[a[x]]++;
sum+=buc[a[x]]*buc[a[x]];
}
void del(int x){
sum-=buc[a[x]]*buc[a[x]];
buc[a[x]]--;
sum+=buc[a[x]]*buc[a[x]];
}
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m>>k;
T=sqrt(n);
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=m;++i){
cin>>q[i].l>>q[i].r;
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int x=1,y=0;
for(int i=1;i<=m;++i){
int qx=q[i].l,qy=q[i].r;
while(x>qx){
x--;
add(x);
}
while(y<qy){
y++;
add(y);
}
while(x<qx){
del(x);
x++;
}
while(y>qy){
del(y);
y--;
}
ansi[q[i].id]=sum;
}
for(int i=1;i<=m;++i) cout<<ansi[i]<<"\n";
return 0;
}
四、例题
CF617E
萌新的第一道莫队维护子区间题
异或有些很好的性质。
- 如果 ,那么
考虑它维护的是区间异或值,所以可以维护前缀异或值。所以问题相当于 ,交换一下得,。这样用个桶维护一下 的出现次数就行。
CF1000F
常规的用桶维护数字的出现次数,如果这个数恰好出现一次就把它放进栈中。输出的时候直接输出栈顶就行,删除的时候可以预先处理它在栈中的位置,然后将它与栈顶交换一下后删除栈顶。
CF877F
又是一道维护子区间的题,所以还是可以用前缀和。前缀和维护的是这一段前缀中第 类问题比第 类多多少。所以问题转化为 。如果这是右端点,也就是已知 ,那么它的贡献就是 的次数。如果这是左端点的同理。由于 的数据范围有点大,所以要离散化一下,还要离散化它的贡献点。
Fibonacci-ish II
[HNOI2016] 大数
依旧是维护子区间的题,所以依旧用前缀和。 表示前 个数组成的数对 取模的值,可以这样递推求出 。这样一段区间对 取模为 可以写成这样的式子:
(两边同时乘以 )
所以我们可以维护一个 表示 。但还需要特判一下 的情况,因为此时最后一个式子并不成立,成立的只有 。
其实这题用后缀和好维护一点,此时的递推式是 。一段区间对 取模为 写成的式子是这样的:
。如果 还是和上面一样特判一下,计算一段区间内有多少个数是以 或 结尾的即可。否则 ,直接算。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下