zoukankan      html  css  js  c++  java
  • BZOJ 3295: [Cqoi2011]动态逆序对 [CDQ分治]

    RT

    传送门


    首先可以看成倒着插入,求逆序对数

    每个数分配时间(注意每个数都要一个时间)$t$,$x$位置,$y$数值

    $CDQ(l,r)$时归并排序$x$

    然后用$[l,mid]$的加入更新$[mid+1,r]$的查询(其实每个数就是一个插入一个查询)

    这里就是前后求逆序对,用树状数组

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,m;
    int mp[N];
    struct Operation{
        int t,x,y;
        Operation(){}
        Operation(int t,int id,int v):t(t),x(id),y(v){}
        bool operator <(const Operation &r)const{
            return x==r.x ? y<r.y : x<r.x;
        }
    }a[N],t[N];
    inline bool cmpTime(const Operation &a,const Operation &b){
        return a.t==b.t ? a.x<b.x : a.t<b.t;
    }
    int c[N];
    inline int lowbit(int x){return x&-x;}
    inline void add(int p,int v){for(;p<=n;p+=lowbit(p)) c[p]+=v;}
    inline int sum(int p){
        int re=0;
        for(;p;p-=lowbit(p)) re+=c[p];
        return re;
    }
    ll ans[N];
    void CDQ(int l,int r){
        if(l==r) return;
        int mid=(l+r)>>1;
        CDQ(l,mid);CDQ(mid+1,r);
        int i=l,j=mid+1,p=l;
        while(i<=mid||j<=r){
            if(j>r||(i<=mid&&a[i]<a[j])) add(a[i].y,1),t[p++]=a[i++];
            else ans[a[j].t]+=sum(n)-sum(a[j].y),t[p++]=a[j++];
        }
        for(int i=l;i<=mid;i++) add(a[i].y,-1);
        for(int i=l;i<=r;i++) a[i]=t[i];
        for(int i=r;i>=l;i--){
            if(a[i].t<=mid) add(a[i].y,1);
            else ans[a[i].t]+=sum(a[i].y);
        }
        for(int i=l;i<=r;i++) if(a[i].t<=mid) add(a[i].y,-1);
    }
    int main(){
        //freopen("inverse.in","r",stdin);
        //freopen("inverse.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=n;i++) a[i]=Operation(0,i,read()),mp[a[i].y]=i;
        int Tim=n;
        for(int i=1;i<=m;i++) a[mp[read()]].t=Tim--;
        for(int i=1;i<=n;i++) if(!a[i].t) a[i].t=Tim--;
        sort(a+1,a+1+n,cmpTime);
        //for(int i=1;i<=10;i++) printf("hi %d %d %d
    ",i,a[i].t,a[i].y);
        CDQ(1,n);
        //for(int i=1;i<=10;i++) printf("ans %d %d
    ",i,ans[i]);
        for(int i=1;i<=n;i++) ans[i]+=ans[i-1];
        for(int i=n;i>=n-m+1;i--) printf("%lld
    ",ans[i]);
    }
    View Code

    【update 2017-03-17】

    前两天学到了删除的姿势,逆序对问题的删除操作不用时间倒流也可以,直接减去它形成的逆序对数并且在树状数组中删除就可以了

    虽然慢一些但是清晰多了

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n,Q,a[N],pos[N],x;
    int m,tim;
    struct meow{
        int t,x,y,type,qid;
        meow(){}
        meow(int a,int b,int c,int d,int e=0):t(a),x(b),y(c),type(d),qid(e){}
        bool operator <(const meow &r) const{
            return x==r.x ? y<r.y : x<r.x;
        }
    }q[N],t[N];
    ll ans[N];
    
    int c[N];
    inline void add(int p,int v) {for(;p<=n;p+=(p&-p)) c[p]+=v;}
    inline int sum(int p) {int re=0; for(;p;p-=(p&-p)) re+=c[p]; return re;}
    
    void CDQ(int l,int r){
        if(l==r) return;
        int mid=(l+r)>>1;
        for(int i=l;i<=r;i++){
            if(q[i].t<=mid) add(q[i].y,q[i].type);
            else ans[q[i].qid]+= q[i].type*( sum(n)-sum(q[i].y) );
        }
        for(int i=l;i<=r;i++) if(q[i].t<=mid) add(q[i].y,-q[i].type);
    
        for(int i=r;i>=l;i--){
            if(q[i].t<=mid) add(q[i].y,q[i].type);
            else ans[q[i].qid]+= q[i].type*sum(q[i].y-1);
        }
        for(int i=l;i<=r;i++) if(q[i].t<=mid) add(q[i].y,-q[i].type);
    
        int p1=l,p2=mid+1;
        for(int i=l;i<=r;i++){
            if(q[i].t<=mid) t[p1++]=q[i];
            else t[p2++]=q[i];
        }
        for(int i=l;i<=r;i++) q[i]=t[i];
        CDQ(l,mid); CDQ(mid+1,r);
    }
    
    int main(){
        freopen("in","r",stdin);
        n=read(); Q=read();
        for(int i=1;i<=n;i++) a[i]=read(), pos[a[i]]=i, q[++m]=meow(++tim, i, a[i], 1, 0);
    
        for(int i=1;i<=Q;i++) x=read(), q[++m]=meow(++tim, pos[x], x, -1, i);
        sort(q+1, q+1+m);
        CDQ(1,m);
        for(int i=1;i<=Q;i++) ans[i]+=ans[i-1],printf("%lld
    ",ans[i-1]);
    }
  • 相关阅读:
    MPS和MRP之间有什么样的关系呢
    java中静态代码块详解
    SQL server 分组后每组取出任意一行
    人是否能成功,其实可能很早就能看出来
    国内外产品经理的区别
    Yarn 和 NPM 国内快速镜像(淘宝镜像)
    vue-cli 使用less 遇到的问题 || vue-cli 使用less
    布隆过滤器
    PHP性能优化
    Redis-高并发代言词,为什么做分布式要Redis?
  • 原文地址:https://www.cnblogs.com/candy99/p/6440745.html
Copyright © 2011-2022 走看看