zoukankan      html  css  js  c++  java
  • [bzoj3295][Cqoi2011]动态逆序对

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

    n<=100000 m<=50000

    呃我感觉我中毒了 看到这道题第一个想法就是对询问分块

    建出主席树,然后把操作压到栈里面,然后每次查询都遍历这个栈,计算答案。然后当操作达到一定数量的时候重建主席树。

    块的大小取大约$sqrt{nlogn}$比较优秀 复杂度$O(m(k+logn)+frac{n}{k}nlogn)$

    当然更靠谱的做法是cdq分治,这道题其实就是一道三维偏序 先对时间排序,然后在分治的时候对x排序,用树状数组/线段树处理y维即可。

    复杂度$O(nlog^{2}n)$

    询问分块

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define mp(x,y) make_pair(x,y)
    #define MN 100000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    ll ans=0,Ans[MN+5];
    int n,m,sz,rt[MN+5],cnt=0,s[MN+5],qx[MN+5],pos[MN+5],q[MN+5],top=0;
    bool b[MN+5];
    struct Tree{int l,r,x;}T[MN*20];
    
    void ins(int x,int nx,int k)
    {
        int l=1,r=n,mid;T[nx].x=T[x].x+1;
        while(l<r)
        {
            mid=l+r>>1;
            if(k<=mid) T[nx].r=T[x].r,T[nx].l=++cnt,r=mid,x=T[x].l,nx=T[nx].l;
            else T[nx].l=T[x].l,T[nx].r=++cnt,l=mid+1,x=T[x].r,nx=T[nx].r;
            T[nx].x=T[x].x+1;
        }
    }
    
    int query(int x,int nx,int k)
    {
        int l=1,r=n,mid,sum=0;
        while(l<r)
        {
            mid=l+r>>1;
            if(k<=mid) x=T[x].l,nx=T[nx].l,r=mid;
            else sum+=(T[T[nx].l].x-T[T[x].l].x),x=T[x].r,nx=T[nx].r,l=mid+1; 
        }
        return sum+T[nx].x-T[x].x;
    }
    
    void build()
    {
        cnt=0;
        for(int i=1;i<=n;i++) 
            b[i]?rt[i]=rt[i-1]:(ins(rt[i-1],rt[i]=++cnt,s[i]),0);
    }
    
    int main()
    {
        n=read();m=read();sz=sqrt(n*15);
        for(int i=1;i<=n;i++) pos[s[i]=read()]=i;
        for(int i=1;i<=m;i++) q[i]=read(),b[pos[q[i]]]=1;
        build();
        for(int i=2;i<=n;i++) if(!b[i])
            ans+=T[rt[i-1]].x-query(0,rt[i-1],s[i]);
        for(int i=m;i;i--)
        {
            if(pos[q[i]]!=1) ans+=T[rt[pos[q[i]]-1]].x-query(0,rt[pos[q[i]]-1],q[i]);
            if(pos[q[i]]!=n) ans+=query(rt[pos[q[i]]],rt[n],q[i]);
            for(int j=1;j<=top;j++)
                if((qx[j]>q[i]&&pos[qx[j]]<pos[q[i]])||(qx[j]<q[i]&&pos[qx[j]]>pos[q[i]])) ++ans;
            Ans[i]=ans;b[pos[q[i]]]=0;
            qx[++top]=q[i];
            if(top>=sz) build(),top=0;
        }
        for(int i=1;i<=m;i++) printf("%lld
    ",Ans[i]);
        return 0;
    }
    View Code

    cdq分治

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define MN 100000
    #define N 131072
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,m,T[N*2+5],ans=0,s[MN+5];ll Ans[MN+5],pos[MN+5];
    struct ques{int kind,t,x,y;}q[MN+5],b[MN+5];
    
    int query(int l,int r)
    {
        int sum=0;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) sum+=T[l+1];
            if( r&1) sum+=T[r-1];
        }
        return sum;
    }
    
    void renew(int x,int ad)
    {
        T[x+=N]+=ad;
        for(x>>=1;x;x>>=1)T[x]=T[x<<1]+T[x<<1|1];
    }
    bool cmpX(ques x,ques y){return x.x<y.x;}
    void solve(int l,int r)
    {
        if(l>=r) return;
        int mid=l+r>>1;
        for(int i=l;i<=r;i++) b[i]=q[i],b[i].kind=(i<=mid)?1:2;
        sort(b+l,b+r+1,cmpX);
        for(int i=l;i<=r;i++) 
            if(b[i].kind==1) renew(b[i].y,1);
            else Ans[b[i].t]+=query(b[i].y,n);
        for(int i=l;i<=r;i++) 
            if(b[i].kind==1)renew(b[i].y,-1);
        for(int i=r;i>=l;i--) 
            if(b[i].kind==1)renew(b[i].y,1);
            else Ans[b[i].t]+=query(1,b[i].y);
        for(int i=l;i<=r;i++) 
            if(b[i].kind==1)renew(b[i].y,-1);  
        solve(l,mid);
        solve(mid+1,r);
    }
    bool cmpT(ques x,ques y){return x.t<y.t;}
    int main()
    {
        n=read();m=read();int tot=n;
        for(int i=1;i<=n;i++)pos[s[i]=read()]=i; 
        for(int i=1;i<=m;i++)q[pos[read()]].t=tot--;
        for(int i=1;i<=n;q[i].x=i,q[i].y=s[i],++i)if(!q[i].t) q[i].t=tot--;
        sort(q+1,q+n+1,cmpT);
        solve(1,n);ll sum=0;
        for(int i=1;i<=n;i++) sum+=Ans[i];
        for(int i=n;i>n-m;i--) printf("%lld
    ",sum),sum-=Ans[i];
        return 0;
    }
    View Code
  • 相关阅读:
    【学习笔记】pip3 安装使用国内源
    【学习笔记】Team Explorer for Microsoft Visual Studio2015 安装时发生严重错误
    微信聊天记录长图 打印
    Go语言中用 os/exec 执行命令的五种姿势
    Python 代码调试神器:PySnooper
    终于来了!!Pyston v2.0 发布,解决 Python 慢速的救星
    超详细讲解如何使用 pdb 在服务器上调试代码
    超详细图文教你如何使用 PyCharm 进行远程调试
    最全的 pip 使用指南,50 % 你可能都没用过~
    学 Python 一定要学会的几个高阶函数
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3295.html
Copyright © 2011-2022 走看看