莫队算法学习笔记
普通莫队
形式¶
假设\(n=m\),那么对于序列上的区间询问问题,如果从\([l,r]\) 的答案能够\(O(1)\) 扩展到 \([l-1,r]\) \([l+1,r]\) \([l,r-1]\) \([l,r+1]\)(即与\([l,r]\) 相邻的区间)的答案,那么可以在\(O(n\sqrt{n})\) 的复杂度内求出所有询问的答案。
实现¶
离线后排序,顺序处理每个询问,暴力从上一个区间的答案转移到下一个区间答案(一步一步移动即可)。
排序方法¶
对于\([l,r]\)区间, 以\(r\) 所在块的编号为第一关键字,\(r\)为第二关键字从小到大排序。
return u.l/m==v.l/m?(u.r==v.r?0:((u.l/m)&1)^(u.r<v.r)):u.l<v.l;//奇偶优化
带修莫队(没实现过)
树上莫队
首先,树上莫队就是维护树上的区间关系,嗯
然后就是引入DFN序列,又或者欧拉序,或入栈出栈序(比较倾向最后一种)
就是到某个点时进队列,出某个点时再进一次队列
考虑上图中的树,其DFS序为
于是,分类讨论(记s[i]为第一个位置,t[i]为第二个位置)
- u,v在同一条链上,查询区间为[s[u],v[v]]或[s[v],s[u]]
- 否则,就是查询[t[u],s[v]]或[t[v],s[u]],再加一个lca
然后具体转移时要记录当前某一个点有几个,还没有就直接加,已经有了一个就减掉(删除同理)
于是就变成了普通莫队
回滚莫队
非常简单
就是考虑只能加入或者只能删除
- 对原序列进行分块,对询问按以左端点所属块编号升序为第一关键字,右端点升序为第二关键字的方式排序。
- 如果询问左端点所属块 B和上一个询问左端点所属块的不同,那么将莫队区间的左端点初始化为 B的右端点加 1, 将莫队区间的右端点初始化为 B的右端点;
- 如果询问的左右端点所属的块相同,那么直接扫描区间回答询问;
- 如果询问的左右端点所属的块不同:
- 如果询问的右端点大于莫队区间的右端点,那么不断扩展右端点直至莫队区间的右端点等于询问的右端点;
- 不断扩展莫队区间的左端点直至莫队区间的左端点等于询问的左端点;
- 回答询问;
- 撤销莫队区间左端点的改动,使莫队区间的左端点回滚到 B的右端点加 1。
copy oi-wiki的