zoukankan      html  css  js  c++  java
  • 莫队算法&BZOJ2038

    题目传送门

    今天看了分块,顺便把基本的莫队学习了一下。

    莫队算法是一种离线算法,复杂度可以达到O((M+N)*Sqrt(N));

    对于询问区间的左端点分块,块内的右端点从小到大排列。

    对区间进行偏移操作。

    掌握一个思想基础:两个询问之间的状态跳转。如图,当前完成的询问的区间为[a,b],下一个询问的区间为[p,q],现在保存[a,b]区间内的每个颜色出现次数的sum[]数组已经准备好,[a,b]区间询问的答案Ans1已经准备好,怎样用这些条件求出[p,q]区间询问的Ans2?

    考虑指针向左或向右移动一个单位,我们要付出多大的代价才能维护sum[]和Ans(即使得sum[],Ans保存的是当前[l,r]的正确信息)。我们美妙地对图中l,r的向右移动一格进行分析:

    l指针向右移动一个单位,所造成的后果就是:我们损失了一个绿色方块。那么怎样维护?美妙地,sum[绿色]减去1。那Ans如何维护?先看分母,分母从n2变成(n-1)2,分子中的其他颜色对应的部分是不会变的,绿色却从sum[绿色]2变成(sum[绿色]-1)2 ,为了方便计算我们可以直接向给Ans减去以前该颜色的答案贡献(即sum[绿色]2)再加上现在的答案贡献(即(sum[绿色]-1)2 )。同理,观赏下面的r指针移动,将是差不多的。

    复杂度分析:

    右端点偏移复杂度不受询问影响,为O(N*Sqrt(N));

    左端点偏移复杂度:因为块的大小为Sqrt(N),所以一次操作最多偏移Sqrt(N),复杂度为O(M*Sqrt(N));

    code:

    /**************************************************************
        Problem: 2038
        User: yekehe
        Language: C++
        Result: Accepted
        Time:1756 ms
        Memory:4256 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
     
    char tc()
    {
        static char tr[100000],*A=tr,*B=tr;
        return A==B&&(B=(A=tr)+fread(tr,1,100000,stdin),A==B)?EOF:*A++;
    }
     
    int read()
    {
        char c;while(c=tc(),c<'0'||c>'9');
        int x=c-'0';while(c=tc(),c>='0'&&c<='9')x=x*10+c-'0';
        return x;
    }
     
    long long gcd(long long x,long long y){return !y?x:gcd(y,x%y);}
     
    long long N,Q,sum[50005],c[50005],ans=0;
    int B[50005],size;
    struct Qr{long long x,y,id;}Qs[50005],A[50005];
    int i,j;
    inline int cmp(Qr x,Qr y){
        return B[x.x]==B[y.x]?x.y<y.y:x.x<y.x;
    }
     
    void updata(int x)
    {
        ans=ans-sum[c[x]]*sum[c[x]];
        sum[c[x]]++;
        ans=ans+sum[c[x]]*sum[c[x]];
    }
     
    void remove(int x)
    {
        ans=ans-sum[c[x]]*sum[c[x]];
        sum[c[x]]--;
        ans=ans+sum[c[x]]*sum[c[x]];
    }
     
    int main()
    {
    //  freopen("x.txt","r",stdin);
        N=read(),Q=read();
        size=sqrt(Q);size+=(size*size<Q);
        long long x,y;
            for(i=1;i<=N;i++)c[i]=read();
            for(i=1;i<=Q;i++)B[i]=(i-1)/size+1;
            for(i=1;i<=Q;i++)x=read(),y=read(),Qs[i]=(Qr){x,y,i};
        sort(Qs+1,Qs+Q+1,cmp);
        int l=1,r=0;
        long long len,As;
            for(i=1;i<=Q;i++){
                while(l>Qs[i].x)updata(--l);
                while(l<Qs[i].x)remove(l++);
                while(r>Qs[i].y)remove(r--);
                while(r<Qs[i].y)updata(++r);
                len=Qs[i].y-Qs[i].x+1;
                x=ans-len,y=len*(len-1);
                if(!x || Qs[i].x==Qs[i].y)
                    {A[Qs[i].id].x=0,A[Qs[i].id].y=1;continue;}
                As=gcd(x,y);x/=As,y/=As;
                A[Qs[i].id].x=x,A[Qs[i].id].y=y;
            }
            for(i=1;i<=Q;i++)
                printf("%lld/%lld
    ",A[i].x,A[i].y);
        return 0;
    }
  • 相关阅读:
    hosts 本机DNS域名解析
    五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程
    OracleBulkCopy
    第三方登录(QQ登录)开发流程详解
    Asp.net MVC中Html.Partial, RenderPartial, Action,RenderAction 区别和用法
    MVC Return View() 和 Return PartialView()的区别
    如何选择Html.RenderPartial和Html.RenderAction
    C# Dictionary和Dynamic类型
    css01入门小例子
    html03表单
  • 原文地址:https://www.cnblogs.com/Cptraser/p/8582143.html
Copyright © 2011-2022 走看看