根号算法——莫队
前置知识
- 分块
前言
莫队算法是由莫涛提出的算法。在莫涛提出莫队算法之前,莫队算法已经在 Codeforces 的高手圈里小范围流传,但是莫涛是第一个对莫队算法进行详细归纳总结的人。莫涛提出莫队算法时,只分析了普通莫队算法,但是经过 OIer 和 ACMer 的集体智慧改造,莫队有了多种扩展版本。
莫队算法可以解决一类离线区间询问问题,适用性极为广泛。同时将其加以扩展,便能轻松处理树上路径询问以及支持修改操作。
形式
假设 \(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\) 排序。
然后,每次考虑 \((l, r)\to (l',r')\)。
每次移动 \(l,r\) 到合适的位置。
但是我们发现如果数据是这样:
(1, 10)
(2, 2)
(3, 10)
(4, 4)
(5, 10)
(6, 6)
(7, 10)
(8, 8)
(9, 10)
(10, 10)
这样我们的算法就变成了 \(O(n^2)\) 的。
所以我们考虑分块,按照所在块的编号排序
比如我们分块: 1 2 3 4 | 5 6 7 | 8 9 10
。
那么排序完变成:
(2, 2)
(4, 4)
(1, 10)
(3, 10)
(6, 6)
(5, 10)
(7, 10)
(8, 8)
(9, 10)
(10, 10)
这样我们的时间复杂度就变成了 \(O(n \sqrt n)\)。