莫队算法

莫队算法的原理讲解,就不多做解释,网上一大片

学习资料推荐:

https://www.luogu.org/blog/codesonic/Mosalgorithm

莫涛大神的知乎

分块思想和时间复杂度

这篇文章的分块思想(如何让L和R这两个指针变得更少)和普通莫队的时间复杂度证明不是很好。

在上篇文章的时候我们提到用分块的思想来优化:对于两个询问,若在其l在同块,那么将其r作为排序关键字,若l不在同块,就将l作为关键字排序(这就是双关键字)

 

也就是说这个序列我们分成了\sqrt{n}块,每一块都x个询问,且这x个询问的右端点是递增的,然后我们先对这一块查找计算。

这样就可以优化时间复杂度么,我们看一下严格的证明(摘自大米饼的博客):

首先,枚举m个答案,就一个m了。设分块大小为unitl

下面给出证明:

我们分类讨论:

①l的移动:若下一个询问与当前询问的l所在的块不同,那么只需要经过最多2*unit步可以使得l成功到达目标.复杂度为:O(m*unit)

②r的移动:r只有在Be[l]相同时才会有序(其余时候还是疯狂地乱跳,你知道,一提到乱跳,那么每一次最坏就要跳n次!),Be[l]什么时候相同?在同一块里面l就Be[]相同。对于每一个块,排序执行了第二关键字:r。所以这里面的r是单调递增的,所以枚举完一个块,r最多移动n次。总共有n/unit个块:复杂度为:O(n*n/unit)

总结:O(n*unit+n*n/unit)(n,m同级,就统一使用n)

根据基本不等式得:当unit为sqrt(n)时,得到莫队算法的真正复杂度:

O(n*sqrt(n))

优化:

快读快写就不说了(很快的)

奇偶性排序

学习文章还提到了:奇偶性排序

莫队算法_第1张图片

这样能快是因为右指针移到右边后不用再跳回左边,而跳回左边后处理下一个块又要跳回右边,这样能减少一半操作,理论上能快一倍

代码:



//return pos[a.l]b.r));///奇偶排序

分块的优化

莫队算法_第2张图片

sz=n/sqrt(m*2/3);

 

普通莫队模板

///莫队算法模板:求区间不同数的个数
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1000005;
typedef long long ll;
int n,m,k;
//莫队算法主要处理离线问题,查询只给出L,R
//当[L,R]很容易向[L-1,R],[L+1,R],[L,R-1],[L,R+1]转移时可用莫队
//注意转移的时候先扩张再收缩,L先向右,L再向左,最后再收缩
//add就是当前区间添加某元素时要做的操作
//del就是当前区间删除某元素时要做的操作
//add,del函数写的时候都要注意结构顺序
struct node
{
    int l,r,id;
}Q[maxn]; ///保存询问值
int pos[maxn];///保存所在块
bool cmp(const node &a,const node &b)
{
   return pos[a.l]b.r));///奇偶排序
   //if(pos[a.l]==pos[b.l]) return a.rQ[i].l) ///前缀和L+1>Q[i].l
        {
            L--;
            add(L);
        }
        while(LQ[i].r)
        {
            del(R);
            R--;
        }
        ans[Q[i].id]=Ans;
    }
    printf("Case %d:\n",cas);
     for(int i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    }
    return 0;
}

带修改的莫队


///带莫队算法模板:求区间不同数的个数+单点修改
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1000005;
typedef long long ll;

void add(int x);
void del(int x);
void modify(int x,int ti);  //这个函数会执行或回退修改ti(执行还是回退取决于是否执行过,具体通过swap实现),x表明当前的询问是x,即若修改了区间[q[x].l,q[x].r]便要更新答案

int sz,cnt[1000010],a[50010],Ans,ans[50010];

struct Change
{
    int p,col;
}c[50010];

struct Query
{
    int l,r,t,id;
    bool operator<(Query& b)
    {
        return l/sz==b.l/sz?(r/sz==b.r/sz?tq[i].l)
        {
            add(a[--l]);
        }
        while (lq[i].r)
        {
            del(a[r--]);
        }
        while (nowq[i].t)
        {
            modify(i,now--);
        }
        
        ans[q[i].id]=Ans;
    }
    
     for (int i=1;i<=qcnt;++i)
     {
        cout<=q[x].l&&c[ti].p<=q[x].r)
    {
        del(a[c[ti].p]);
        add(c[ti].col);
    }
    swap(a[c[ti].p],c[ti].col); 
}

例题:

【BZOJ 2038 [2009国家集训队]小Z的袜子(hose)】    (莫队算法+数学公式)

Codeforces617 E . XOR and Favorite Number            (莫队算法+异或)

1188 - Fast Queries                                                       (莫队算法)

NBUT 1457 Sona                                                        (莫队算法+离散化)

Codeforces - 220B Little Elephant and Array             (莫队模板题+离散化)

codeforces 86D. Powerful array                                   (莫队算法)

P1903 [国家集训队]数颜色 / 维护队列                      (带修莫队算法模板:求区间不同数的个数+单点修改)

codeforces 940f Machine Learning                               【 带修改莫队+离散化】

你可能感兴趣的:(莫队算法,模板)