zoukankan      html  css  js  c++  java
  • BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

    BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

    Description

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

    Input

    输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
    以下n行每行包含一个1到n之间的正整数,即初始排列。
    以下m行每行一个正整数,依次为每次删除的元素。
    N<=100000 M<=50000

    Output

    输出包含m行,依次为删除每个元素之前,逆序对的个数。

    Sample Input

    5 4
    1
    5
    3
    4
    2
    5
    1
    4
    2

    Sample Output

    5
    2
    2
    1
    样例解释
    (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。


    设每个值v删除的时间为t,位置为p。

    对于那些没有删除的值,可以当成删除时间为n+1。

    于是我们要统计删除一个数后逆序对数量变少了多少。

    即统计删除时间大于tx,位置小于px,值大于vx的y的个数。

    删除时间大于tx,位置大于px,值小于vx的y的个数。

    按删除时间从大到小排序,然后CDQ分治内部按位置排序,分别统计这两部分。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 100050
    typedef long long ll;
    int b[N],pos[N],n,m,c[N],is[N];
    ll ans[N],lstans;
    struct A {
        int t,p,v;
    }a[N],t[N];
    bool cmp(const A &x,const A &y) {
        return x.t>y.t;
    }
    void fix(int x,int v) {for(;x<=n;x+=x&(-x)) c[x]+=v;}
    ll inq(int x) {ll re=0;for(;x;x-=x&(-x)) re+=c[x]; return re;}
    void solve(int l,int r) {
        if(l==r) return ;
        int mid=(l+r)>>1;
        solve(l,mid); solve(mid+1,r);
        int i=l,j=l,k=mid+1;
        while(j<=mid&&k<=r) {
            if(a[j].p<a[k].p) fix(a[j].v,1),t[i++]=a[j++];
            else ans[a[k].t]+=inq(n)-inq(a[k].v),t[i++]=a[k++];
        }
        while(j<=mid) fix(a[j].v,1),t[i++]=a[j++];
        while(k<=r) ans[a[k].t]+=inq(n)-inq(a[k].v),t[i++]=a[k++];
        for(i=l;i<=mid;i++) fix(a[i].v,-1);
         
        j=mid,k=r;
        while(j>=l&&k>=mid+1) {
            if(a[j].p>a[k].p) fix(a[j].v,1),j--;
            else ans[a[k].t]+=inq(a[k].v-1),k--;
        }
        while(j>=l) fix(a[j].v,1),j--;
        while(k>=mid+1) ans[a[k].t]+=inq(a[k].v-1),k--;
        for(i=l;i<=mid;i++) fix(a[i].v,-1);
        for(i=l;i<=r;i++) a[i]=t[i];
    }
    int main() {
        scanf("%d%d",&n,&m);
        int i,j;
        for(i=1;i<=n;i++) scanf("%d",&b[i]),lstans+=i-1-inq(b[i]),pos[b[i]]=i,fix(b[i],1);
        memset(c,0,sizeof(c));
        for(i=1;i<=m;i++) {
            scanf("%d",&a[i].v); a[i].p=pos[a[i].v]; a[i].t=i; is[a[i].v]=1;
        }
        for(j=m,i=1;i<=n;i++) {
            if(!is[i]) a[++j]=(A){n+1,pos[i],i};
        }
        sort(a+1,a+n+1,cmp);
        solve(1,n);
        //for(i=1;i<=m;i++) printf("%lld
    ",ans[i]);
        for(i=1;i<=m;i++) printf("%lld
    ",lstans),lstans-=ans[i];
    }
    
  • 相关阅读:
    STM32的GPIO工作原理 | 附电路图详细分析
    话说上拉电阻和下拉电阻
    Linux下MySQL数据库常用基本操作
    Linux acpi off学习的必要
    CentOS 6.2出现Disk sda contains BIOS RAID metadata解决方法
    降低开关电源纹波的三个要素
    什么是RFID? 射频识别技术的特点及工作原理!
    亲测可用的国内maven镜像
    Linux 删除文件夹和文件的命令
    [Gradle] 在 Eclipse 下利用 gradle 构建系统
  • 原文地址:https://www.cnblogs.com/suika/p/9219578.html
Copyright © 2011-2022 走看看