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

    学习笔记 莫队

    讲解

    某大佬的博客
    里面讲的很详细

    解决问题

    主要解决序列上的问题
    比如区间的不同元素个数等等乱七八糟的

    主要方法

    通过离线把区间分块排序来让暴力效率更高
    哪怕是待修也可以通过增加一维解决

    排序比较函数

    一般的:

    inline bool cmp(node a,node b) {
        return bl[a.l]==bl[b.l] ? a.r < b.r : bl[a.l] < bl[b.l];
    }
    

    有一定优化的:
    先按照左端点的块排序假如块是奇数的时候右端点递增,否则递减

    inline bool cmp1(node x,node y){
        return (bl[x.l]^bl[y.l]) ? bl[x.l]<bl[y.l] : (bl[x.l]&1) ? x.r<y.r : x.r>y.r;
    }
    

    待修的:
    增加了一维

    inline bool cmp1(node x,node y){
        return (bl[x.l]^bl[y.l]) ? bl[x.l]<bl[y.l] : ((bl[x.r]^bl[y.r]) ? bl[x.r]<bl[y.r] : x.ti < y.ti);
    }
    

    例题

    SP3267 DQUERY - D-query

    很正常的莫队,直接就是板子一样的
    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=30010,maxm=1e6+10;
    int m,n,a[maxm],bl[maxm],ans[maxm],cnt[maxm];
    struct node{
        int l,r,id;
    }q[maxm];
    inline bool cmp1(node x,node y){
        return (bl[x.l]^bl[y.l]) ? bl[x.l]<bl[y.l] : (bl[x.l]&1) ? x.r<y.r : x.r>y.r;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int sz=sqrt(n);
        int bln=ceil((double)n/sz);
        for(int i=1;i<=bln;i++)
            for(int j=(i-1)*sz+1;j<=min(n,i*sz);j++) bl[j]=i;
        scanf("%d",&m);
        for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
        sort(q+1,q+1+m,cmp1);
        int l=1,r=0,now=0;
        for(int i=1;i<=m;i++){
            int ql=q[i].l,qr=q[i].r;
            while(l<ql) now-=!--cnt[a[l++]];
            while(l>ql) now+=!cnt[a[--l]]++;
            while(r<qr) now+=!cnt[a[++r]]++;
            while(r>qr) now-=!--cnt[a[r--]];
            ans[q[i].id]=now;
        }
        for(int i=1;i<=m;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    

    Luogu_P2709 小B的询问

    需要推一下加减的式子
    代码如下:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=50010;
    int n,m,k,a[maxn],bl[maxn],cnt[maxn];
    ll now=0,ans[maxn];
    struct node{
        int l,r,id;
    }e[maxn];
    inline bool cmp1(node x,node y){
        return (bl[x.l]^bl[y.l]) ? bl[x.l]<bl[y.l] : (bl[x.l]&1) ? x.r<y.r : x.r>y.r;
    }
    inline void add(int x){
        cnt[a[x]]++;
        now+=(ll)2*cnt[a[x]]-1;
    } 
    inline void del(int x){
        cnt[a[x]]--;
        now-=(ll)2*cnt[a[x]]+1;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=m;i++) scanf("%d%d",&e[i].l,&e[i].r),e[i].id=i;
        int sz=sqrt(n);
        int bln=ceil((double)n/sz);
        for(int i=1;i<=bln;i++)
            for(int j=sz*(i-1)+1;j<=min(n,sz*i);j++) bl[j]=i;
        sort(e+1,e+1+m,cmp1);
        int l=1,r=0;
        for(int i=1;i<=m;i++){
            int ql=e[i].l,qr=e[i].r;
            while(l<ql) del(l++);
            while(l>ql) add(--l);
            while(r<qr) add(++r);
            while(r>qr) del(r--);
            ans[e[i].id]=now;
        }
        for(int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
        return 0;
    }
    

    P1903 [国家集训队]数颜色 / 维护队列

    带修的,增加一维。
    要是不把add和del加入主函数会T,挺卡常然而我O2

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=200003,maxcnt=1e6+10;
    int n,m,a[maxn],bl[maxn],qcnt,ccnt,now=0,ans[maxn],cnt[maxcnt];
    struct node{
        int l,r,ti,id;
    }q[maxn];
    struct edge{
        int wh,cl;
    }c[maxn];
    inline bool cmp1(node x,node y){
        return (bl[x.l]^bl[y.l]) ? bl[x.l]<bl[y.l] : ((bl[x.r]^bl[y.r]) ? bl[x.r]<bl[y.r] : x.ti < y.ti);
    }
    inline void add(int x){
        if(!cnt[a[x]]) now++;
        cnt[a[x]]++;
    }
    inline void del(int x){
        cnt[a[x]]--;
        if(!cnt[a[x]]) now--;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int sz=pow(n,(double)2.0/3.0);
        int bln=ceil((double)n/sz);
        for(int i=1;i<=bln;i++)
            for(int j=sz*(i-1)+1;j<=min(n,sz*i);j++) bl[j]=i;
        for(int i=1;i<=m;i++){
            char s[10];scanf("%s",s);
            if(s[0]=='Q'){
                ++qcnt;scanf("%d%d",&q[qcnt].l,&q[qcnt].r);
                q[qcnt].ti=ccnt;q[qcnt].id=qcnt;
            }else{
                ++ccnt;scanf("%d%d",&c[ccnt].wh,&c[ccnt].cl);
            }
        }
        sort(q+1,q+1+qcnt,cmp1);
        int l=1,r=0,tme=0;now=0;
        for(int i=1;i<=qcnt;i++){
            int ql=q[i].l,qr=q[i].r,qt=q[i].ti;
            while(l<ql) del(l++);
            while(l>ql) add(--l);
            while(r<qr) add(++r);
            while(r>qr) del(r--);
            while(tme<qt){
                ++tme;
                if(ql<=c[tme].wh && c[tme].wh<=qr) {
                    cnt[a[c[tme].wh]]--;
                    if(!cnt[a[c[tme].wh]]) now--;
                    if(!cnt[c[tme].cl]) now++;
                    cnt[c[tme].cl]++;
                }
                swap(a[c[tme].wh],c[tme].cl);
            }
            while(tme>qt){
                if(ql<=c[tme].wh && c[tme].wh<=qr) {
                    cnt[a[c[tme].wh]]--;
                    if(!cnt[a[c[tme].wh]]) now--;
                    if(!cnt[c[tme].cl]) now++;
                    cnt[c[tme].cl]++;
                }
                swap(a[c[tme].wh],c[tme].cl);
                --tme;
            }
            ans[q[i].id]=now;
        }
        for(int i=1;i<=qcnt;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    

    易错点(我的)

    cnt数组开不够空间
    now的加减

  • 相关阅读:
    [leetcode-648-Replace Words]
    [leetcode-647-Palindromic Substrings]
    [leetcode-646-Maximum Length of Pair Chain]
    [leetcode-645-Set Mismatch]
    [leetcode-459-Repeated Substring Pattern]
    [leetcode-636-Exclusive Time of Functions]
    [leetcode-644-Maximum Average Subarray II]
    iOS开发之使用XMPPFramework实现即时通信(三)
    Oracle 内置sql函数大全
    Oracle 中的sql函数以及分页
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11685837.html
Copyright © 2011-2022 走看看