zoukankan      html  css  js  c++  java
  • P2709-小B的询问-(莫队算法)

    莫队算法被称为优雅的暴力,是一种 毒瘤暴力的 区间操作算法。初学莫队,记录一下思想。

    对于多个区间查询[l,r]这类问题,可以离线操作,常规做法还有对左区间或者右区间从小到大排序,让左指针或者右指针只走一遍,有效降低时间复杂度。但是遇到[1,1000000],[2,3],[3,1000000],[4,5],[5,1000000]这样的查询区间,虽然可以保证左区间只扫一遍,但是右指针需要从头到尾来回扫,时间复杂度一下子就上去了。莫队算法就是专门针对这种毒瘤题目的。

    它的主要思想是分块,对区间的范围n开根号得到一个d,每一个查询区间[l,r]的左区间l除以d,区间看作是全局的第x块,不同块按的区间块从小到大排序,同一块的按右区间从小到大排序(不同块看左,同块看右)。分块排序写一个自定义比较函数就可以了。时间复杂度n*sqrt(n),具体证明看其他大佬博客吧。

    对于查询的区间[l,r],指针移动操作比较常规,无非是左指针和右指针左右移动,[5,7]的答案可以由[5,8]或者[5,6]移动一次右指针解决,也可以由[4,7]或[6,7]移动一次左指针解决。对于区间查询的贡献,减去原来的,加上现在的。

    入门题P2709

    题意看了很久才懂,解释一下数据,1到4出现了2个1,对答案贡献2*2,出现1个2,对答案贡献1*1,出现1个3,对答案贡献1*1,加起来就是6。

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<math.h>
    #include<string>
    #include<map>
    #include<queue>
    #include<stack>
    #include<set>
    #include<ctime>
    #define ll long long
    #define inf 0x3f3f3f3f ///填充无限小-0x7f
    using namespace std;
    
    struct node
    {
        int l;
        int d;
        int r;
        int idx;
        ll ans;
    };
    node b[50005];
    int a[50005];
    int num[50005];
    int n,m,k;
    int d;
    
    
    bool cmp1(node p1,node p2)///分块,对左区间开根号,左边不在同一块按左区间小到大排序,左边在同一块按右边大小排序
    {
        if(p1.d<p2.d)
            return true;
        else if(p1.d==p2.d)
            return p1.r<p2.r;
        else
            return false;
    }
    
    bool cmp2(node p1,node p2)///离线操作后恢复答案次序
    {
        return p1.idx<p2.idx;
    }
    
    
    int main()///P2709 莫队入门
    {
        scanf("%d%d%d",&n,&m,&k);
        d=sqrt(n);///开根号的分块标准
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            b[i].l=l;
            b[i].d=l/d;///分块
            b[i].r=r;
            b[i].idx=i;
        }
    
        sort(b+1,b+m+1,cmp1);
        int L=1,R=1;
        num[ a[1] ]=1;
        ll ans=1;
        for(int i=1;i<=m;i++)
        {
            while(L>b[i].l)///左指针往左
            {
                L--;
                ans=ans-num[ a[L] ]*num[ a[L] ];///减去原来的计数贡献
                num[ a[L] ]++;
                ans=ans+num[ a[L] ]*num[ a[L] ];///加上新的计数贡献
            }
            while(L<b[i].l)///左指针往右
            {
                ans=ans-num[ a[L] ]*num[ a[L] ];
                num[ a[L] ]--;
                ans=ans+num[ a[L] ]*num[ a[L] ];
                L++;
            }
            while(R<b[i].r)///右指针往右
            {
                R++;
                ans=ans-num[ a[R] ]*num[ a[R] ];
                num[ a[R] ]++;
                ans=ans+num[ a[R] ]*num[ a[R] ];
            }
            while(R>b[i].r)///右指针往左
            {
                ans=ans-num[ a[R] ]*num[ a[R] ];
                num[ a[R] ]--;
                ans=ans+num[ a[R] ]*num[ a[R] ];
                R--;
            }
            b[i].ans=ans;
        }
    
        sort(b+1,b+m+1,cmp2);
        for(int i=1;i<=m;i++)
            printf("%lld
    ",b[i].ans);
    
    
        return 0;
    }
  • 相关阅读:
    BeautifulSoup中的select方法
    BeautifulSoup中的find,find_all
    python中sys.stdout、sys.stdin
    python sort、sorted
    Numpy常用操作
    pandas (loc、iloc、ix)的区别
    小波变化库——Pywalvets学习笔记
    python filter()函数
    Redis数据库总结
    高逼格企业级MySQL数据库备份方案,原来是这样....
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/12829251.html
Copyright © 2011-2022 走看看