学习笔记:莫队算法(还有给自己的坑)

简述

有人说莫队算法说是一个优雅的暴力,很有道理,我认为是一个优雅的分块。

作用

对于有些线段树等高级数据结构无法维护的操作,就考虑用莫队吧。

毕竟这是一个O(n^1.5)的算法,肯定功能比log的强大。

适用范围

  1. 离线
  2. 可以在知道[L,R]的情况下,快速推出[L+1,R],[L-1,R],[L,R+1],[L,R-1]的情况。

算法原理

先对询问排序,然后暴力转移每一个询问。

排序方式:先把序列分块,然后按照l的块为第一关键字,r为第二关键字进行排序。

时间复杂度

O((n+m)*n^0.5)
可以直接当做 O(n^1.5)

分析如下:

设n为长度,m为询问次数,t1为块数,t2为块长,t1*t2=n;

右端点移动:
对于左端点在一个块中时,右端点最坏情况是从尽量左到尽量右,所以右端点时间复杂度O(n),左端点一共可以在t1个块中,所以又端点总时间复杂度O(t1*n)

左端点移动:
在同一块中,移动不会超过O(t2),块之间移动不会超过O(2 * t2 ),所以最终也就是O(m*t2)。

每次询问时间复杂度一般来说是O(1),当然也要看你选择的数据结构,一共m次。

总共就是:修改时间( t1 n + t2 * m)+查询时间*m

一般情况下我们让t1=t2吧,所以就是O((n+m)*n^0.5),有时候直接认为是O(n ^ 1.5)

实际效果要好一些,因为分块的话时间是不会抵满的。

要注意修改和查询操作的时间复杂度分析。

代码

注意:
1. L,R最初是空区间,闭区间可以用下面啊的技巧表示空区间。
2. 在修改的时候L,R先改还是先动有考究(扩大区间先动,缩小区间先改),这样可以保证区间时刻都有长度,当然你的修改比较厉害可以处理负区间就无所谓了。

void modui()
{
    int L=1,R=0;
    for(int i=1;i<=m;i++)
    {
        while(L<q[i].l)blo.del(co[L++]);
        while(L>q[i].l)blo.add(co[--L]);
        while(R<q[i].r)blo.add(co[++R]);
        while(R>q[i].r)blo.del(co[R--]);
        ans[q[i].id]=blo.query(q[i].a,q[i].b);
    }
}

超级简单。

有空补树上莫队

你可能感兴趣的:(学习笔记/板子,莫队,高级数据结构板子)