zoukankan      html  css  js  c++  java
  • 神奇的根号--莫队算法

    神奇的根号–莫队算法


    莫队这个根号我觉得是比分块灵活的,就在于他有许多的方式


    0.先决条件

    莫队的先决条件,在我看来就是两个
    1:可以从区间[l,r]快速转移到[l,r+1][l,r1][l+1,r][l1,r]
    2:时间允许O(nsqrt(n))

    1.普通莫队

    简单莫队 。
    因为我们可以发现我们从[l,r]转移到[l1,r1]的次数是abs(l1l)+abs(r1r),像极了曼哈顿距离,所以我们把每一个关于区间的询问抽象成二维平面上的点,然后用根号为块的大小进行询问的划分(证明网上一大堆),因为每次改变左、右端点是O(1)这样我们就可以简单期望效率是O(nsqrt(n))
    板子题也是一大堆,这里不列举

    2.带修莫队

    不是那么简单的莫队。
    考虑当我们的操作加入了修改?我们应该怎么办?
    修改操作是不和谐的,因为修改相当于是在本来的二维平面上强行有添加了一个维度,所以我们只有给每个询问或者秀改操作加上时间标记,当我们执行修改的事就就可以跳到当前我们的时间,这样我们就可以进行维护了,但是我们发现在这种情况下块的大小不是最优的,所以我们把块的大小调整为n2/3
    这里给出复杂度为n5/3的简单证明:
    当左右端点所在块不变时,询问是按时间排序的,因此询问的时间不降,所以时间指针只会向后移动n步,而左右两端点改变时时间指针最坏情况下会一次向前移动n步。而由于左右两端点所在块的种类组合起来只有n2/3种,且每种组合中,时间指针只会向后移动n步;取值改变也只有n2/3次,时间指针每次向前移动n步,时间指针的总复杂度即为n5/3
    左右端点所在块不变时,右指针一次移动最多n2/3步,由于有n次询问,所以这里的复杂度不超过n5/3 。而当左端点所在块不变,右端点所在块改变时,右指针就不会往回移动到前一个块中,因此左端点所在块不变,由于右端点所在块改变所带来的的移动的复杂度不超过n,而总共有n1/3种左端点所在块取值,所以这里的复杂度不超过n4/3,而当左端点所在块改变时,右指针最坏是一次移动n步,与之前类似,总共有n1/3种左端点所在块取值,所以这里的复杂度不超过n4/3。右指针总时间复杂度为n5/3
    左端点所在块不变时,左指针一次移动最多n2/3步,由于有n次询问,所以这里的复杂度不超过n5/3 。当左端点所在块改变时,由于排序是按左端点所在块为第一关键字,所以之后左指针就不会移动回前一个块,因此这种情况下的左指针移动带来的总复杂度不超过n,左指针总时间复杂度也为n5/3
    综上,这个拓展的做法的总时间复杂度即为n5/3

    模板:BZOJ2120


    3.树上莫队

    建成树的莫队。
    有时我们所处理的问题并不为序列上的区间问题,而是树上的路径。那么实际上我们也可以把莫队算法拓展到树上,即树上莫队。
    核心思想依旧没变,因此我们需要考虑的仍是如何将询问排序。而常用方法则是将树上的点标号,使其变为序列,然后用普通的莫队算法解决。
    解决时唯一不同的则是原来序列上用的是左右指针移动,现在树上这个方法不太好用,因为左边或右边可能都与当前位置节点不相邻,并不是我们需要维护的路径上的东西。
    所以我们应该怎么办?
    观察后可以发现:
    而从(u1,v1)转移到(u2,v2) 我们需要把(u1,u2)路径上除了lca(u1,u2)之外的点在答案中的状态取反,把(v1,v2)路径上除了lca(v1,v2)之外的点在答案中的状态取反。通过画图或者简单推导我们能现在,这么做后,剩下的在答案中的点,都在(u2,v2)它们之间的除去lca之外的路径上。
    复杂度证明真不会,可以参见vfk博客中的证明。

    对点进行标号的方法一般有两种:
    1.我们DFS 这棵树,同时记录下它们的入栈出栈序,对这个序列进行分块
    2.对树分块(对树进行DFS,每个点出栈后将其放进队列,当队列里的点超过B 个时将这些点分为一块)

    个人偏爱第二种

    模板题BZOJ3052,树上带修莫队,代码丢失了。。。。

    //qwq

    4.回滚莫队

    科技莫队。
    跟yyf大佬学的。dalao blog
    在莫队转移过程中,如果我们发现删除操作不好进行,那么我们就可以用回滚莫队技巧来回避掉删除操作
    我们在左端点blocki中的所有讯问,容易发现右端点是单调不减的,所以我们可以每次都把左端点从blocki的右端点向前跑,然后右端点直接向后跑就可以了。注意在这里先跑右端点记录下左端点在blocki的右端点的答案方便后面的计算。
    然后考虑特殊情况,如果一个询问左右端点在同一区间,暴力跑过去就好了,时间效率上限是块的大小。如果一个询问左端点所在的块不等于上一个询问的左端点所在块,即进入了一个新的块,我们直接从这个询问的l跑到r记录答案就好了,单次O(n),因为块数为sqrt(n),所以时间上线还是O(nsqrt(n))

    模板题直接看今天的考试题好了。。
    或者BZOJ4241也行

  • 相关阅读:
    COGS727 [网络流24题] 太空飞行计划
    Bzoj1692 洛谷P2870 [Usaco2007 Dec]队列变换
    Bzoj1029 [JSOI2007]建筑抢修
    Bzoj3168 [Heoi2013]钙铁锌硒维生素
    Bzoj4566 [Haoi2016]找相同字符
    Bzoj4771 七彩树
    Bzoj2597 [Wc2007]剪刀石头布
    Bzoj4773 负环
    HDU5772 String problem
    Bzoj1324 Exca王者之剑
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676336.html
Copyright © 2011-2022 走看看