满足无区间修改可离线,可**$O(1)$得到相邻区间的计数**,即可$O(qlogq+n^{\frac{3}{2}})$求出q个查询区间$[l,r],1≤l≤r≤n$

普通莫队

算法流程

将长度为n的区间分成约$\sqrt n$个块,每块的大小最多为$\lfloor\sqrt n\rfloor$。确定每个查询的左端点所属块号,若第i个查询为$[l_i,r_i]$,$l_i$确定的块号$\frac{l_i}{\lfloor\sqrt n\rfloor}$

将q个查询进行排序,若左端点所属块号相同,则按照右端点升序排序;否则按照左端点所属块号升序排序。

初始双指针$l=1,r=0$。查询排序后,对于第i次查询$[l_i,r_i]$,将$l$移动到$l_i$,将$r$移动到$r_i$。此过程中维护区间计数。注意不能出现$l>r$的情况,所以代码实现中移动判断的顺序有讲究。

双指针移动的时间复杂度为$O(n \sqrt n)$

我们分别考虑左右指针的移动次数。

对于右指针,在区间左端点所属同一块的区间右端点移动时间复杂度为$O(n)$,共$O(\sqrt n)$分块,总时间复杂度为$O(n\sqrt n)$

若分块共计分成sz块,区间左端点分配到第i块的个数为$a_i$,对于第i块中的左端点由于是无序的,我们考虑最坏的移动情况,就是每次移动需要跨越整个块,这时候所需的时间复杂度为$O(a_i\sqrt n)$。所有块所需时间复杂度$O(\sum \limits_{i=1}^{sz} a_i \sqrt n) = O(n \sqrt n)$

回滚莫队

普通莫队需要删除,有时候删除操作比较难维护,需要花更多时间。

回滚莫队直接移除删除操作,只有添加。

算法流程

对于查询区间左右端点属于同一块号,则直接暴力计算

剩余查询区间排序:若左端点所属块号相同,则按照右端点升序排序;否则按照左端点所属块号升序排序。

对于左端点属于同一块号的区间:右端点是向右增长的,只有添加操作;左端点变化是在同一块内抖动,采用普通莫队会有删除操作,但是回滚莫队,每次计算完左端点后都将左端点退回到该块的最右端。

template