zoukankan      html  css  js  c++  java
  • 【BZOJ】3295: [Cqoi2011]动态逆序对

    【题意】给定1~n的排列,m次操作每次删除一个数,求每次操作前的逆序对数。n<=10^5,m<=50000。

    【算法】CDQ分治+树状数组

    【题解】先树状数组求逆序对,然后统计每次删除的逆序对数。

    每个数字及其坐标构成一个二维坐标,逆序对就是两个相对位置在左上右下的点,那么删除一个点会减少的逆序对就是其左上偏序和右下偏序中的点数,转化为有操作顺序的二维平面矩阵查询和单点修改,用CDQ分治或树套树解决。

    具体细节:

    1.先加入所有加点操作(原数字必须作为最开始的操作进入CDQ分治过程),再加入前m-1个删除和询问。

    2.第一次统计右下偏序,按x轴逆序排序后CDQ分治。

    3.第二次统计左上偏序,令所有点y=n-y+1,然后按x轴正序排序后CDQ分治。

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define lowbit(x) (x&-x)
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    const int maxn=100010;
    int n,m,ans[maxn],c[maxn],t[maxn],A[maxn],tot=0;
    struct cyc{int id,kind,qid,x,y;}a[maxn*2],b[maxn*2];
    long long ANS=0;
    void modify(int x,int k){for(int i=x;i<=n;i+=lowbit(i))c[i]+=k;}
    int query(int x){int as=0;for(int i=x;i>=1;i-=lowbit(i))as+=c[i];return as;}
    bool cmp(cyc a,cyc b){return a.x<b.x||(a.x==b.x&&a.id<b.id);}
    bool cmp2(cyc a,cyc b){return a.x>b.x||(a.x==b.x&&a.id<b.id);}
    void CDQ(int l,int r){
        if(l==r)return;
        int mid=(l+r)>>1;
        for(int i=l;i<=r;i++){
            if(a[i].id<=mid&&!a[i].kind)modify(a[i].y,a[i].qid?-1:1);
            if(a[i].id>mid&&a[i].kind)ans[a[i].qid]+=query(a[i].y);
        }
        for(int i=l;i<=r;i++)if(a[i].id<=mid&&!a[i].kind)modify(a[i].y,a[i].qid?1:-1);
        int x1=l-1,x2=mid;
        for(int i=l;i<=r;i++)if(a[i].id<=mid)b[++x1]=a[i];else b[++x2]=a[i];
        for(int i=l;i<=r;i++)a[i]=b[i];
        CDQ(l,mid);CDQ(mid+1,r);
    }    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            A[i]=read();
            t[A[i]]=i;
            modify(A[i],1);
            ANS+=i-query(A[i]);
        }
        if(m>1)printf("%lld
    ",ANS);
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)a[++tot]=(cyc){tot,0,0,i,A[i]};
        for(int i=1;i<m;i++){
            int x=read();
            a[++tot]=(cyc){tot,0,i,t[x],x};
            a[++tot]=(cyc){tot,1,i,t[x],x};
        }
        sort(a+1,a+tot+1,cmp2);
        CDQ(1,tot);
        for(int i=1;i<=tot;i++)a[i].y=n-a[i].y+1;
        sort(a+1,a+tot+1,cmp);
        CDQ(1,tot);
        for(int i=1;i<m;i++){
            ANS-=ans[i];
            printf("%lld
    ",ANS);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    parallel desktop ubuntu从18.04更新到20.04(包括安装Parallels Tools)
    一段奇怪的R代码
    ipynb(jupyter notebook)的git管理的比较好的方式
    对比jupyterlab和jupyter notebook
    dotfiles的管理
    macvim报出一些奇怪的错误: macvim只能从命令行启动
    CSS3学习笔记(三、选择器-续)
    CSS3学习笔记(二、选择器)
    CSS3学习笔记(一、CSS介绍、语法、引入方式)
    HTML学习笔记(四、body内常用标签)
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8215263.html
Copyright © 2011-2022 走看看