zoukankan      html  css  js  c++  java
  • 莫队算法

      莫队算法是由之前的国家队队长莫涛发明,故称为莫队算法。其用于处于静态区间查询。

    区间莫队

      对于区间查询,我们一般会使用主席树或树套树之类吊炸天的数据结构来进行处理。这是基于我们可以对区间进行二分,并通过分治的方式保证拥有对数级别的性能。当然前提是查询的内容要适合进行分治处理,对于形如最大值最小值,分治非常适合,但是也有非常不适合的,譬如我们要查询区间中重复次数最多的数值,这时候分治就失去了意义。这时候莫队算法就站了出来。

      对于上面的问题,如果在已知[l,r]上每个数字的重复次数,那么对于[l,r+1],[l,r-1],[l+1,r],[l-1,r]上的询问,可以在O(1)的时间复杂度内解决。直接按序执行查询,其时间复杂度将可能达到O(mn),其中n为区间长度,m为查询数目。莫队算法则需要对查询进行重新组织。定义两个查询[a,b]与[x,y]的距离为|a-x|+|b-y|,即二者的曼哈顿距离。如果我们将每个查询视作一个顶点,而两个查询之间的距离视作两个结点间的边长,将查询[0,0]视作起点,那么要发挥莫队算法的完全性能,我们需要找到从起点出发的一条经过所有顶点的最短路径。但是要找这样的一条路径显然是费事费力的,因此我们会选择另外一种方法-分块,降低莫队算法的时间复杂度。分块是这样的,我们将[1,n]均分为n/k个长度为k的块。之后我们对查询进行排序,排序的第一关键字是查询左边界所处的块的编号,而第二关键字是查询右边界。之后我们按排序好的结果逐一执行查询请求。

      时间复杂度的证明如下:

      对于每一个块,由于左边界落于该块中的查询的右边界递增,故右边界最多移动n次。由于总共有n/k个块,故最多移动n^2/k次。

      对于每一个块,由于左边界落于该块中的查询切换时,左边界最多移动k次,而总共切换最多发生m次,因此左边界最多移动km次。

      在一个块处理完进入另外一个块的时候,我们可能需要完全重置当前维护的区间的信息,即左右边界最多加总移动2n次,由于最多发生n/k次,故最多移动2n^2/k次。

      综合上面可知总的时间复杂度为O(nlog2(n))+O(km)+O(n^2/k)=O(nlog2(n)+km+n^2/k)。当m很小的时候,我们完全可以选择k为n,这时候时间复杂度为O(nlog2(n)),而当m较大时,我们可以选择k为1,此时时间复杂度为O(n^2+m)。下面是理论上应该选取的最优k值,仅用到简单的微分技巧:

    $$ fleft(k ight)=nlog_2n+km+n^2/k $$ $$ f'left(k ight)=m-n^2/k^2 $$ $$ f'left(k ight)=0Rightarrow mk^2=n^2Rightarrow k=n/sqrt{m} $$

    此时的时间复杂度为$ Oleft(ncdotleft(log_2n+sqrt{m} ight) ight) $。

    带修改莫队

      我们完全可以令莫队算法支持修改。假设区间长度为N,查询次数为Q,修改次数为M。查询和修改的次序任意。利用与一般莫队相同的方案。我们将区间按长度a进行切分,而将区间按长度b进行切分。对于每个查询,称其之前发生的修改次数为该查询的版本,记作(l,r,v),其中v为版本号。我们对查询进行分块,一个块中的所有查询(l,r,v),其l/a向下取整均相同,且v/b向下取整也相同。首先我们将所有查询(l,r,v)进行排序,排序的第一关键字是l/a向下取整,第二关键字是v/b向下取整,而第三关键字为r。之后依序执行查询。

      时间复杂度的证明如下:

      对于每一个块,右边界最多移动N次,而块数为N*M/(a*b),故执行次数为M*N^2/(a*b)。

      对于每一个块中的查询,左边界和版本号最多分别改变a次和b次,即块中查询执行次数为Q*(a+b)。

      对于块之间的切换,每次左边界和版本号最多修改2*a次和2*b次,即块间切换执行次数为Q*(a+b)。

      综合以上可见时间复杂度为O(M*N^2/(a*b)+Q*(a+b))。利用微分技巧可知:

    $$
    frac{df}{da}=-frac{MN^2}{left( ab ight) ^2}cdot b+Q=0Rightarrow a^2b=frac{MN^2}{Q}
    $$

    考虑到式子对于a和b是对称的,因此可以推出当下式成立时

    $$
    frac{df}{da}=frac{df}{db}=0
    $$

    必定有a=b。故可以得出

    $$
    a=b=sqrt[3]{frac{N^2M}{Q}}
    $$

    此时代入原来时间复杂度式子中可以得出最优的时间复杂度为$Oleft( N^{frac{2}{3}}M^{frac{1}{3}}Q^{frac{2}{3}} ight)$,由于一般Q=M,此时时间复杂度为$Oleft( N^{frac{2}{3}}M ight) $。

  • 相关阅读:
    codevs 2632 非常好友
    codevs 1213 解的个数
    codevs 2751 军训分批
    codevs 1519 过路费
    codevs 1503 愚蠢的宠物
    codevs 2639 约会计划
    codevs 3369 膜拜
    codevs 3135 River Hopscotch
    数论模板
    JXOJ 9.7 NOIP 放松模拟赛 总结
  • 原文地址:https://www.cnblogs.com/dalt/p/8306523.html
Copyright © 2011-2022 走看看