• [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
  • 相关阅读:
    swift 第十四课 可视化view: @IBDesignable 、@IBInspectable
    swift 第十三课 GCD 的介绍和使用
    swift 第十二课 as 的使用方法
    swift 第十一课 结构体定义model类
    swift 第十课 cocopod 网络请求 Alamofire
    swift 第九课 用tableview 做一个下拉菜单Menu
    swift 第八课 CollectView的 添加 footerView 、headerView
    swift 第七课 xib 约束的优先级
    swift 第六课 scrollview xib 的使用
    swift 第五课 定义model类 和 导航栏隐藏返回标题
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3295.html
Copyright © 2020-2023  润新知