模板

参考一下czq的博客:https://www.cnblogs.com/JHSeng/p/10862295.html

(不带修的)莫队算法适用于什么问题?当然是不带修改的区间查询。莫队算法通过离线所有查询,然后对查询进行分块,在查询与查询之间暴力转移。

假如可以通过维护区间端点的信息,从 ([l,r]) 的状态 (O(1)) 转移到 ([l pm 1,r]) 以及 ([l,r pm 1]) ,则可以从 ([l_1,r_1]) 的状态 (O(|l_1-l_2|+|r_1-r_2|)) 转移到 ([l_2,r_2]) ,莫队算法就是离线所有的这些查询,然后根据某种次序去回答这些查询,使得转移的距离比较少。注意到假如把 (l) 看做横坐标, (r) 看做纵坐标,那么查询就是二维平面上的点,总的转移距离最少的就是曼哈顿距离最小生成树。

据说在莫队的论文中指出了在最坏情况下,使用曼哈顿距离最小生成树解决这个问题的复杂度和分块是一样的,只是常数比较小,那么就不需要这么麻烦了。

分块的思路是:按每 (sqrt n) 大小分为一块,左端点不在同一块中的,按左端点的从小到大排序,左端点在同一块中的,按右端点从小到大排序。比如一组 ([1,9]) 上的查询 ([1,9],[2,4],[2,5],[3,3],[3,7],[4,5],[5,7],[6,8],[8,9]) 按照上面的思路排序就是:

第一个块:([3,3],[2,4],[2,5],[1,9]) ,易知左端点总的转移数不超过 (O(sqrt n)) ,右端点总的转移数不超过 (O(n)) 。在块与块之间的转移,左端点的转移数不超过 (O(sqrt n)) (并且这里转移了会预支下一个分块的转移),右端点的转移数不超过 (O(n)) 。每个分块都是一样的,共有 (O(sqrt n)) 个分块,所以总的复杂度为 (O(nsqrt n))

也就是说,这个算法由下面的部分组成:

1、离线查询的区间的 (l,r,id,ans) ,ans用来存放答案。
2、写一个按 (l,r) 端点排序的函数,和一个按 (id) 排序的函数。
3、分别写好“吐出左端点”、“吐出右端点”、“吃进左端点”、“吃进右端点”四种转移。
4、算法主体,排序查询,然后写四个while
5、重新排序查询

原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12490436.html