学习笔记——莫队
前言
莫队算法是一种优雅的暴力算法,因其发明人是国家队队长莫涛,所以叫莫队算法。他是通过离线询问的方式将询问分块,再暴力维护的一种数据结构。
算法
思想:先离线将每一个询问存储下来,将其按区间左端点从小到大(左端点相同则比较右端点)的顺序排序,之后维护两个指针\(l,r\)暴力维护每一个区间即可。
时间复杂度:因为一共分成了\(\sqrt{n}\)个块,最坏情况下从每一个块的起点遍历到序列的右端点,则复杂度为\(O(n\sqrt{n})\)。
例题:
本题为莫队板子,照着题面直接模拟即可。
P5268 [SNOI2017]一个简单的询问(题解)(我的代码)
本题运用差分,可以将\(get(l_1,r_1,x)\)转化为\(get(1,r_1,x)-get(1,l_1-1,x)\),令\(g(i,x)=get(1,i,x)\),则原式可以转化为
然后拆成四份分别用莫队进行求解。
带修莫队
思想:对于每一次修改操作,我们可以引入一个时间戳代表是第几次修改,离线后我们就可以维护三个指针\(l,r,time\),当三个指针都移动到正确位置后再统计答案。
注意:此时块长设为\(\sqrt[3]{n^4t}\) 才可达到最佳复杂度\(O(n^{\frac{5}{3}})\)
例题
P1903 [国家集训队]数颜色 / 维护队列(题解)(我的代码)
树上莫队
思想:莫队可以处理一维的序列问题,对于树上的问题,我们也可以运用\(dfs\)序将其转化为一位的序列再进行求解。
例题
SP10707 COT2 - Count on a tree II(题解)(我的代码)
本题要对树上的两点路径进行操作,所以我们引入欧拉序:在遍历整棵树时该节点第一次被遍历则加入序列,遍历完其子树后再将其加入序列。
通过欧拉序,我们就可以统计\(u,v\)在欧拉序中第一次出现的位置的区间内只出现过一次的点,即为\(u,v\)两点的路径。
注意:若\(u,v\)两点的\(LCA\)不是\(u\)或\(v\),则需要统计\(u\)最后一次出现到\(v\)第一次出现的区间内只出现一次的点,这些点才是\(u,v\)两点的路径。
P4689 [Ynoi2016] 这是我自己的发明(题解)(我的代码)
本题是P5268 [SNOI2017]一个简单的询问的树上加强版,我们同样可以运用\(dfs\)序将树上的问题转化到一个序列中进行求解。
对于换根操作,我们可以分类讨论:
-
\(root\)不在\(u\)的子树内,则该区间就是以1为根的树\(u\)所对应的子树的区间。
-
\(root\)在\(u\)的子树内,则需要找到\(u\)的一个儿子节点\(v\),使\(root\)在\(v\)的子树中,则区间为[1,n]减去\(v\)所在子树所包含的区间。
设\(f(a,b,c,d)\)为\([a,b]\)和\([c,d]\)两区间内点权相同的个数和,\(g(x,y)=f(1,x,1,y)\),\(h(i)=g(i,n)\)
- \(u,v\)都是一段区间:
- \(u,v\)一个为一段区间,另一个为两段区间
- \(u,v\)都是两段区间:
本题是树上带修莫队,同样使用欧拉序将树上两点间路径转化为区间内出现奇数次的节点,套带修莫队板子进行维护即可。
回滚莫队
思想:对于一些添加至容易但删除困难的操作,我们可以每一次将\(l\)移动到区间的右端点\(+1\)的位置,将\(r\)移动到右端点,因为莫队的排序中将左端点在同一块中的所有查询区间右端点单调递增排序,所以我们可以用正常的莫队方法移动右端点,再记录当前的\(res\)(设为\(tmp\)),暴力将左端点移动至正确位置,统计答案后将左端点移回区间的右端点\(+1\)的位置,将\(res\)改为\(tmp\)即可。
例题
P5906 【模板】回滚莫队&不删除莫队(题解)(我的代码)
学习资料
博客:莫队算法——从入门到黑题
题单:【算法】莫队


浙公网安备 33010602011771号