• BZOJ 3295 【CQOI2011】 动态逆序对


    Description

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

    Input

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

    Output

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

    HINT

    $n leq 100000$   $m leq 50000$

      这道题做法很多……但是我来做这道题只是为了练CDQ分治的……

      首先,我们可以考虑当删除一个数之后逆序对数减少了多少。不难发现,减少的逆序对数就是 这个数 前面比它大的数的个数 加上 后面比它小的数的个数。

      那么,如果我们强行把最后数列中剩下的数也删掉,那么我们就得到了$n$个操作,用 $(x_i,y_i,z_i)$ 表示操作$i$是在时刻$z$把$y$位置上值为$x$的数给删掉。

      于是,对于一个操作$i$,这个操作减少的逆序对数为 $x_j>x_i,y_j<y_i,z_j>z_i$以及$x_j<x_i,y_j>y_i,z_j>z_i$的$j$的个数。

      其实这就是一个三维偏序。对于两个式子分别在CDQ分治的时候扫一遍即可。 大概的思路就是排序一维,分治时归并一维,剩下一维再用树状数组来维护。

      下面贴代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
     7 #define maxn 100010
     8 
     9 using namespace std;
    10 typedef long long llg;
    11 
    12 struct data{
    13     int x,y,b;
    14     bool operator < (const data &h)const{return x>h.x;}
    15 }s[maxn],ss[maxn];
    16 int c[maxn],n,m,a[maxn],ans[maxn];
    17 bool w[maxn]; llg ana;
    18 
    19 int getint(){
    20     int w=0;bool q=0;
    21     char c=getchar();
    22     while((c>'9'||c<'0')&&c!='-') c=getchar();
    23     if(c=='-') c=getchar(),q=1;
    24     while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    25     return q?-w:w;
    26 }
    27 
    28 void add(int x,int y){while(x<=n) c[x]+=y,x+=x&(-x);}
    29 int sum(int x){
    30     int t=0;
    31     while(x) t+=c[x],x-=x&(-x);
    32     return t;
    33 }
    34 
    35 void solve(int l,int r){
    36     if(l>=r) return;
    37     int mid=l+r>>1,now=l,kk=l-1,k1=l,k2=mid+1;
    38     solve(l,mid); solve(mid+1,r);
    39     for(int i=mid+1;i<=r;i++){
    40         while(s[now].y<s[i].y && now<=mid) add(s[now].b,1),now++;
    41         ans[s[i].b]+=sum(n)-sum(s[i].b);
    42     }
    43     for(int i=l;i<now;i++) add(s[i].b,-1);
    44     now=r;
    45     for(int i=mid;i>=l;i--){
    46         while(s[now].y>s[i].y && now>mid) add(s[now].b,1),now--;
    47         ans[s[i].b]+=sum(n)-sum(s[i].b);
    48     }
    49     for(int i=now+1;i<=r;i++) add(s[i].b,-1);
    50     while(k1<=mid && k2<=r)
    51         if(s[k1].y<s[k2].y) ss[++kk]=s[k1++];
    52         else ss[++kk]=s[k2++];
    53     while(k1<=mid) ss[++kk]=s[k1++];
    54     while(k2<=r) ss[++kk]=s[k2++];
    55     for(int i=l;i<=r;i++) s[i]=ss[i];
    56 }
    57 
    58 int main(){
    59     File("a");
    60     n=getint(); m=getint();
    61     for(int i=1;i<=n;i++) a[getint()]=i;
    62     for(int i=1;i<=m;i++){
    63         s[i].x=getint(); s[i].b=i;
    64         s[i].y=a[s[i].x]; w[s[i].x]=1;
    65     }
    66     for(int i=1,t=m;i<=n;i++)
    67         if(!w[i]){
    68             s[++t].x=i; s[t].b=t;
    69             s[t].y=a[s[t].x];
    70         }
    71     sort(s+1,s+n+1); solve(1,n);
    72     for(int i=1;i<=n;i++) ana+=ans[i];
    73     for(int i=1;i<=m;i++){
    74         printf("%lld
    ",ana);
    75         ana-=ans[i];
    76     }
    77 }
  • 相关阅读:
    linux环境安装es插件elasticsearch-head
    Linux环境安装安装NodeJS v10.16.3
    几种常见的关系型和非关系型数据库
    在window下安装Redis数据库,并用python链接Redis
    数据库锁机制
    脏读,不可重复读,幻读,丢失更新
    bit, byte, KB, GB, TB, PB, EB, ZB, YB, BB, NB, DB, CB, XB
    shell 替换字符串的几种方法,变量替换${},sed,awk
    国内外短信接码平台合集
    canvas获取浏览器指纹-唯一的设备标识
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/5877465.html
Copyright © 2020-2023  润新知