神奇的根号--莫队算法
神奇的根号–莫队算法
莫队这个根号我觉得是比分块灵活的,就在于他有许多的方式
0.先决条件
莫队的先决条件,在我看来就是两个
1:可以从区间快速转移到
2:时间允许
1.普通莫队
简单莫队 。
因为我们可以发现我们从转移到的次数是,像极了曼哈顿距离,所以我们把每一个关于区间的询问抽象成二维平面上的点,然后用根号为块的大小进行询问的划分(证明网上一大堆),因为每次改变左、右端点是这样我们就可以简单期望效率是
板子题也是一大堆,这里不列举
2.带修莫队
不是那么简单的莫队。
考虑当我们的操作加入了修改?我们应该怎么办?
修改操作是不和谐的,因为修改相当于是在本来的二维平面上强行有添加了一个维度,所以我们只有给每个询问或者秀改操作加上时间标记,当我们执行修改的事就就可以跳到当前我们的时间,这样我们就可以进行维护了,但是我们发现在这种情况下块的大小不是最优的,所以我们把块的大小调整为。
这里给出复杂度为的简单证明:
当左右端点所在块不变时,询问是按时间排序的,因此询问的时间不降,所以时间指针只会向后移动步,而左右两端点改变时时间指针最坏情况下会一次向前移动步。而由于左右两端点所在块的种类组合起来只有种,且每种组合中,时间指针只会向后移动步;取值改变也只有次,时间指针每次向前移动步,时间指针的总复杂度即为。
左右端点所在块不变时,右指针一次移动最多步,由于有次询问,所以这里的复杂度不超过 。而当左端点所在块不变,右端点所在块改变时,右指针就不会往回移动到前一个块中,因此左端点所在块不变,由于右端点所在块改变所带来的的移动的复杂度不超过,而总共有种左端点所在块取值,所以这里的复杂度不超过,而当左端点所在块改变时,右指针最坏是一次移动步,与之前类似,总共有种左端点所在块取值,所以这里的复杂度不超过。右指针总时间复杂度为 。
左端点所在块不变时,左指针一次移动最多步,由于有次询问,所以这里的复杂度不超过 。当左端点所在块改变时,由于排序是按左端点所在块为第一关键字,所以之后左指针就不会移动回前一个块,因此这种情况下的左指针移动带来的总复杂度不超过,左指针总时间复杂度也为
综上,这个拓展的做法的总时间复杂度即为
模板:BZOJ2120
3.树上莫队
建成树的莫队。
有时我们所处理的问题并不为序列上的区间问题,而是树上的路径。那么实际上我们也可以把莫队算法拓展到树上,即树上莫队。
核心思想依旧没变,因此我们需要考虑的仍是如何将询问排序。而常用方法则是将树上的点标号,使其变为序列,然后用普通的莫队算法解决。
解决时唯一不同的则是原来序列上用的是左右指针移动,现在树上这个方法不太好用,因为左边或右边可能都与当前位置节点不相邻,并不是我们需要维护的路径上的东西。
所以我们应该怎么办?
观察后可以发现:
而从转移到 我们需要把路径上除了之外的点在答案中的状态取反,把路径上除了之外的点在答案中的状态取反。通过画图或者简单推导我们能现在,这么做后,剩下的在答案中的点,都在它们之间的除去lca之外的路径上。
复杂度证明真不会,可以参见vfk博客中的证明。
对点进行标号的方法一般有两种:
1.我们DFS 这棵树,同时记录下它们的入栈出栈序,对这个序列进行分块
2.对树分块(对树进行DFS,每个点出栈后将其放进队列,当队列里的点超过B 个时将这些点分为一块)
个人偏爱第二种
模板题BZOJ3052,树上带修莫队,代码丢失了。。。。
//qwq
4.回滚莫队
科技莫队。
跟yyf大佬学的。dalao blog
在莫队转移过程中,如果我们发现删除操作不好进行,那么我们就可以用回滚莫队技巧来回避掉删除操作
我们在左端点中的所有讯问,容易发现右端点是单调不减的,所以我们可以每次都把左端点从的右端点向前跑,然后右端点直接向后跑就可以了。注意在这里先跑右端点记录下左端点在的右端点的答案方便后面的计算。
然后考虑特殊情况,如果一个询问左右端点在同一区间,暴力跑过去就好了,时间效率上限是块的大小。如果一个询问左端点所在的块不等于上一个询问的左端点所在块,即进入了一个新的块,我们直接从这个询问的l跑到r记录答案就好了,单次,因为块数为,所以时间上线还是