zoukankan      html  css  js  c++  java
  • 莫队学习笔记

      

      莫队是针对区间操作问题的一种算法,利用一种近乎QJ(骗分神技)测试点的剪枝方法,强行使程序的时间复杂度降一个根号。

      

      算法基础:

        1、分块:分块是莫队的来源,利用分块思想,可以将询问分块,达到缩短查询区间,降低时间复杂度的目的。

        2、结构体关键字排序:莫队的精髓所在,通过对询问区间排序,可以减少指针的移动总距离,使总复杂度较为优秀。

        3、单调指针的简单应用:莫队的重要工具,通过两个指针的扫描,可以由前一区间转移到该区间,统计答案。

        4、离散化:数据范围极大时能起到巨大的优化作用,缩小总区间,使指针的移动更加快捷高效。

        5、卡常技巧:哎嘿嘿~~(其实莫队本质上是个暴力QwQ)。

      

      算法实现: 

        首先我们来看一个例题:

    题目描述

    image

    输入格式

    image

    输出格式

    image

    样例

    样例输入

    3 4
    1 2 2
    1 2 1 3
    1 2 1 1
    1 3 1 3
    2 3 2 3
    

    样例输出

    2 2
    1 1
    3 2
    2 1
    
     

    数据范围与提示

    N=100000,M=1000000

     
     
       观察题面,我们发现,这不过是一道区间操作问题。
      首先考虑暴力思路,对于每一个询问,直接扫描对应区间即可。但是$O(nm)$的复杂度证明这肯定不是正解qwq。
       那我们考虑优化,因为该题不需要修改,所以任意区间的答案相当于是固定的。
      那我们可不可以用我们已知答案的区间,来更新出我们询问的区间呢?
      答案是可以的,这也就是莫队算法的由来。
      考虑如何更新新的区间,可以想到用两个树状数组维护每个区间中在[l,r]中的数值,及不同的权值数量,每次将指针移动,更新状态即可。
    #include<bits/stdc++.h>
    #define re register
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    int n,m,bel[1000005],size,tot,data[1000005];
    int tr1[4000005],tr2[4000005],cnt[1000005];
    int la[1000005],ra[1000005];
    struct node{int l,r,a,b,id,la,ra;}q[1000005];
    inline bool cmp(node a,node b)
    {return (bel[a.l]^bel[b.l])?bel[a.l]<bel[b.l]:((bel[a.l]&1)?a.r<b.r:a.r>b.r);}
    inline int read(){
        re int a=0,b=1;re char ch=getchar();
        while(ch<'0'||ch>'9')
            b=(ch=='-')?-1:1,ch=getchar();
        while(ch>='0'&&ch<='9')
            a=(a<<3)+(a<<1)+(ch^48),ch=getchar();
        return a*b;
    }
    inline void add1(re int x,re int y){
        for(;x<=m;x+=lowbit(x)) tr1[x]+=y;
    }
    inline int getsum1(re int x){
        re int res=0;
        for(;x;x-=lowbit(x)) res+=tr1[x];
        return res;
    }
    inline void add2(re int x,re int y){
        for(;x<=m;x+=lowbit(x)) tr2[x]+=y;
    }
    inline int getsum2(re int x){
        re int res=0;
        for(;x;x-=lowbit(x)) res+=tr2[x];
        return res;
    }
    inline void inc(re int x){
        if(++cnt[x]==1)add2(x,1);add1(x,1);
    }
    inline void del(re int x){
        if(--cnt[x]==0)add2(x,-1);add1(x,-1);
    }
    signed main(){
        n=read(),m=read();
        size=sqrt(n);
        tot=(n+size-1)/size;
        for(re int i=1;i<=tot;i++)
            for(re int j=(i-1)*size+1;j<=i*size;j++)
                bel[j]=i;
        for(re int i=1;i<=n;i++) data[i]=read();
        for(re int i=1;i<=m;i++) 
            q[i].l=read(),q[i].r=read(),q[i].a=read(),q[i].b=read(),q[i].id=i;
        sort(q+1,q+m+1,cmp);
        re int l=q[1].l,r=q[1].r;
        for(re int i=l;i<=r;i++) inc(data[i]);
        la[q[1].id]=getsum1(q[1].b)-getsum1(q[1].a-1);
        ra[q[1].id]=getsum2(q[1].b)-getsum2(q[1].a-1);
        for(re int i=2;i<=m;i++){
            while(l<q[i].l)del(data[l++]);
            while(l>q[i].l)inc(data[--l]);
            while(r<q[i].r)inc(data[++r]);
            while(r>q[i].r)del(data[r--]);
            la[q[i].id]=getsum1(q[i].b)-getsum1(q[i].a-1);
            ra[q[i].id]=getsum2(q[i].b)-getsum2(q[i].a-1);
        }
        for(re int i=1;i<=m;i++)
            printf("%d %d
    ",la[i],ra[i]);
        return 0;
    }
    Ahoi 作业

       此,我们可以把莫队算法理解为一种优雅的暴力,只不过它的剪枝极为巧妙,达到了理想的效果。

      
      以上仅为静态莫队,相应的还有带修莫队、树上莫队、回滚莫队、二维莫队等,在这里先咕掉了。。。(溜...
     
     
  • 相关阅读:
    SAP Tax Service可以取代TAXBRA / RVABRA吗?(翻译) 跨国贸易云税务解决方案
    SAP Brazil J1BTAX 为税收例外创建税收组(翻译)
    WordPress 安装插件导致 HTTP 500 内部服务器错误的问题
    12 Best Live Chat Software for Small Business Compared (2019) 最佳的wordpress在线聊天工具推荐插件 来帮你和潜在客户互动
    一个虚拟主机或空间实现放多个网站的方法【非常实用】
    用WordPress建立专业网站教程 (一步步建站, 一步也不少)
    阿里云+wordpress搭建个人博客网站【小白专用的图文教程】- 【转发】 AWS云和WordPress搭建个人博客网站
    【原创】SAP/Oracle 集团企业海外全球化实施注意事项: 一带一路本地化 (持续更新)
    AI人工智能顶级实战工程师 课程大纲
    联想项目结束了,聊聊华为SAP HANA项目八卦
  • 原文地址:https://www.cnblogs.com/Hzoi-lyl/p/11660429.html
Copyright © 2011-2022 走看看