回滚莫队详解
会了莫队可以了解一下回滚莫队,这玩意可以解决莫队解决不了的问题, 而且莫队能解决的它都能解决,还好写一点。
不过没用学过莫队也没关系, 这玩意比莫队简单还好用。
下面详细的说下回滚莫队的流程。
假设现在有一个长度为 n n n的序列和 q q q次询问,每次询问都是查询 [ l , r ] [l, r] [l,r]区间, 具体查询什么已经不重要了。
考虑离线。
首先将长度为 n n n的序列进行分块,根据数学知识为 n \sqrt{n} n是最优的
想在将所有的 [ l , r ] [l, r] [l,r]按 l l l分块, 对于每同一快的 [ l , r ] [l, r] [l,r] 按 r r r从小到大排序。
比如现在 l l l在第一快有三组区间,分别是: [ l 1 , r 1 ] , [ l 3 , r 3 ] , [ l 2 , r 2 ] [l_1, r_1], [l_3, r_3], [l_2, r_2] [l1,r1],[l3,r3],[l2,r2]。
然后按照
r
r
r从小到大排序(如下图)
按照 r r r从小到大排完序后,第一组询问就是 [ 1 1 , r 1 ] [1_1, r_1] [11,r1],第二组询问为 [ l 2 , r 2 ] [l_2, r_2] [l2,r2],第三组询问是 [ l 3 , r 3 ] [l_3, r_3] [l3,r3]
- 先查询第一组询问 [ l 1 , r 1 ] [l_1, r_1] [l1,r1], 由于 l 1 l_1 l1和 r 1 r_1 r1在同一块,直接暴力求解 [ l 1 , r 1 ] [l_1, r_1] [l1,r1]的答案, 对于这一组询问最坏的情况复杂度为 O ( n ) O(\sqrt{n}) O(n)。
- 在查询第二组询问 [ l 2 , r 2 ] [l_2,r_2] [l2,r2],由于 l 1 l1 l1和 r 1 r1 r1不在同一快,先暴力查询 [ l 1 , R ] [l_1, R] [l1,R](其中 R R R是第一快最右边的位置), 然后再用一个指针暴力查询 [ R + 1 , r 2 ] [R + 1, r2] [R+1,r2]区间答案并保存,留着下次查询再用(这就是之前按 r r r从小到大排序的原因),然后将两次查询的结构进行合并就是 [ l 2 , r 2 ] [l_2, r_2] [l2,r2]的区间答案。
- 最后第三次查询, 和上面一样暴力 [ l 3 , R ] [l_3, R] [l3,R]的区间, 因为之前查询了 [ R + 1 , r 2 ] [R + 1, r_2] [R+1,r2]的信息且结果也保存了,那么这次只要查询 [ r 2 + 1 , r 3 ] [r_2 + 1, r_3] [r2+1,r3]的信息即可, 将两次查询结果进行合并就是答案了。
我们了算一下对于第一快查询的复杂度, 如果查询区间再同一快类,那么询问就是 n \sqrt{n} n,如果不在一个区间暴力查询 [ l , R ] [l, R] [l,R]的区间是 n \sqrt{n} n, 而查询 [ R + 1 , r ] [R+1, r] [R+1,r]的信息,因为之前按 r r r从小到大排序,也就是对于每一块总共的复杂度是 O ( n ) O(n) O(n), 但是总共也就 n \sqrt{n} n快, 所以总共的复杂度为 O ( q ∗ n + s ) O(q*\sqrt{n} + s) O(q∗n+s)