浅谈莫队

所谓莫队,就是莫涛队长发明的算法。

这是一种什么算法呢?首先你得会分块:https://www.cnblogs.com/AKMer/p/10369816.html

是不是开始吐槽分块的博客写的啥玩意儿了……没事,莫队不会那么“浅”。

便于本人偷懒,以下假设序列长度与询问个数同阶。

只处理询问的莫队算法

莫队用于处理序列上的区间询问问题,基于我们可以由([l,r])的答案通过(O(1))的复杂度得到([lpm1,r])([l,rpm1])的答案,莫队算法将一个个询问区间进行排序后可以使得复杂度较暴力得到大大的优化,是一种十分优美的暴力。

首先我们将序列进行分块,每一块大小为(size),一共有(T=n/size)块。

然后我们将询问进行排序,按照左端点所在块为第一关键字,右端点为第二关键字升序排序。那么总复杂度就是相邻询问的左端点之差的绝对值的和加上右端点之差的绝对值的和。如果我们每次用(nowl,nowr)两个指针卡住当前询问区间,并且向下一个询问区间移动,那么总复杂度就是这俩指针移动的步数。

首先,块内左端点每次移动不会超过(size),一共(n*size)步;块与块之间移动的步数总和不会超过(n),所以左端点移动的复杂度是(O(n*size))的。

其次,对于左端点在同一块内,右端点严格上升,只会移动(n)步,就算左端点的块变化了,那一步也是(n),所以右端点的复杂度是(O(Tn))的。

那么莫队算法的复杂度就是(O(n*size+Tn))的。由于基本不等式(frac{a+b}{2}geqslantsqrt{ab})(a=b)时取最小值,所以当(n*size=n/size*n)时复杂度取最小值,解之得(size=sqrt{n})

所以莫队算法的复杂度是(O(nsqrt{n}))的。

既要处理询问又要处理修改的莫队算法

这一次我们还是把每一块分为(size)大小,一共有(T=n/size)块。

对于询问和修改,我们还加上第三关键字,那就是时间(时间先的修改会对后面的询问造成影响)。

这一次我们按照左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字升序排序。对于两个询问,我们不断要暴力移动左右端点,还要暴力还原修改或者进行修改。如果当前询问比下一个询问要先,那么就把在这两个时间点内的修改操作全部修改掉,否则就把这两个时间点内的修改操作全部还原掉。

对于修改,每个左端点块相同,右端点块相同的组合是严格升序的,也就是会造成(O(n))的贡献,那么就一共有(O(T^2n))的复杂度。

与只询问的莫队相同,左端点的复杂度是(O(n*size))的,右端点是(O(n*size+T*n))的。

所以总复杂度是(O(T^2n+n*size+T*n)),忽略最后那个(T*n)就是(O(T^2n+n*size))的。

还是根据基本不等式,解出来(size=n^{frac{2}{3}})。那么复杂度就是(O(n^{frac{5}{3}}))的。

树上莫队

把树上路径问题搬到欧拉序上来,每个点存一个(L_u)(R_u)表示欧拉序(带回溯的(dfs)序)上第一次和第二次出现的位置。

假设(u)(v)(lca),那么他们之间的路径信息可以通过欧拉序上([L_u,L_v])来统计。

假设(u)(v)不存在谁是谁的(lca)关系,那么他们之间的路径信息可以通过欧拉序上的([R_u,l_v])加上单独计算(lca)来统计。

我说过莫队不会那么“浅”就肯定不会那么“浅”。

原文地址:https://www.cnblogs.com/AKMer/p/10374756.html