莫队
莫队是离线算法,所以不能用于强制在线的题目。
| 词 | 精确含义 | 判断方法 |
|---|---|---|
| 聚合(可合并信息,或者说是半群) | 存在很小的可以表示出答案的状态(\(\mathcal O(1)\) 或 \(\mathcal O(\log n)\) 个数)和一个结合运算,并且大的状态可以通过子状态合并 | 原问题答案可以通过子问题的少量信息合并得出 |
| 集合 | 答案依赖数据的实际分布 |
普通莫队
可以在 \(\mathcal O(n\sqrt m)\) 的时间复杂度下解决 \(m\) 组区间询问,要求移动左右端点时可以 \(\mathcal O(1)\) 增量计算。
具体实现就是每 \(\dfrac{n}{\sqrt m}\) 分个块,按区间左端点所在的块为第一关键字,右端点位置为第二关键字给询问排序,然后暴力移动左右端点指针,注意先扩大区间再缩小区间。
对于左端点,要么在一个块内反复横跳要么移动到下一个块,最坏情况下,左端点移动次数是 \(mB+n\)。对于右端点,对于左端点在相同块内的,只会向右移动,总移动次数不超过 \(n\)。而左端点所在的块变化时可能会移动到很左边,但是块数限制了重置次数。最坏情况下,右端点移动次数是 \(\dfrac{2n^2}{B}\)。
根据基本不等式,\(mB+n+\dfrac{2n^2}{B}\geq \sqrt{2mn^2}+n\),忽略掉 \(2\),当 \(B\) 取 \(\dfrac{n}{\sqrt m}\) 时,时间复杂度最优为 \(\mathcal O(n\sqrt m)\)。(注意 \(n,m\) 的位置顺序)
带修莫队
普通莫队不支持修改,但加上时间这个维度就行了,忘记怎么排序了,好像是前两位按块,最后一位按下标。然后块长是 \(\sqrt[3]{n^2}\)。
回滚莫队
有时候,指针移动可能只支持扩大/缩小,即只支持插入/删除。但是要支持撤销。
每次都从 \([R,r]\) 出发,\(R,r\) 分别为某个块的右端点和当前右端点指针。先右移右端点,然后左移左端点,记录答案后将左端点撤销会 \(R\)。
\(\max,\operatorname{mex}\) 等是支持撤销的。\(\max\) 这种不可差分的撤销就是记录每个位置的 \(\max\) 值是多少,撤销时返回历史版本。
莫队二次离线
对于普通莫队能处理,但是单次移动指针的时间代价为 \(\mathcal O(k)\) 的问题,可以用莫队二次离线优化为 \(\mathcal O(nk+n\sqrt m)\)。
要求贡献可差分。
以 \([l,r]\) 移动到 \([l,r+k]\) 为例,这是增加的贡献就是 \(\sum_{i=r+1}^{r+k}f_{i,l,i-1}\),\(f_{x,l,r}\) 的意思是 \(x\) 和 \([l,r]\) 产生的贡献。将原式差分:\(\sum_{i=r+1}^{r+k}f_{i,1,i-1}-\sum_{i=r+1}^{r+k}f_{i,1,l-1}\),前者可以预处理,后者存下来扫描线。
以下是模板题的关键代码:
struct node{
int l,r,x,id,v;
}op[Q<<1];int cnt;
bool cmp2(node x,node y){
return x.x<y.x;
}
void solve(){
int lst=0;
sort(op+1,op+cnt+1,cmp2);
for(int i=1;i<=cnt;i++){
node x=op[i];
while(lst<x.x)upd(a[++lst],1);
for(int i=x.l;i<=x.r;i++)ans[x.id]+=x.v*qry(a[i]);
}
return;
}
int l=1,r=0;
for(int i=1;i<=m;i++){
if(r<q[i].r)
ans[q[i].id]+=b[q[i].r]-b[r],
op[++cnt]=((node){r+1,q[i].r,l-1,q[i].id,-1}),r=q[i].r;
if(r>q[i].r)
ans[q[i].id]-=b[r]-b[q[i].r],
op[++cnt]=((node){q[i].r+1,r,l-1,q[i].id,1}),r=q[i].r;
if(l>q[i].l)
ans[q[i].id]-=b[l-1]-b[q[i].l-1]+(k?0:l-q[i].l),
op[++cnt]=((node){q[i].l,l-1,r,q[i].id,1}),l=q[i].l;
if(l<q[i].l)
ans[q[i].id]+=b[q[i].l-1]-b[l-1]+(k?0:q[i].l-l),
op[++cnt]=((node){l,q[i].l-1,r,q[i].id,-1}),l=q[i].l;
}
树上莫队
询问变成树上路径。
将树转欧拉序转成区间问题,欧拉序是在每个点第一次被访问和访问结束的时候记录下这个点,欧拉序上两点首次出现的位置构成的区间内出现了恰好一次的点就出现在两点的树上路径上,特殊地,这两点和 LCA 也要加上。

浙公网安备 33010602011771号