【bzoj3295 动态逆序对】

Description

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

Input

  输入第一行包含两个整数nm,即初始元素的个数和删除的元素个数。以下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

题解

  这题我调了一小时,有一个细节写爆了。

  说说怎么说吧。cdq分治。(因为做这类题才能想到)

  如果要离线,那就反过来考虑每个数加入能产生出多少逆序对,所以要与那些插入过的数比较。

  那么一个数插入产生的逆序对数就是已经插入的数中位置比它小值比它大的个数加上已经插入的数中位置比它大值比它小的个数。

  那么就有想法了就是把x为插入次序,y为数值,z为位置。(x1<x说明当x这个数要插入的时候x1已经在序列中了)

  就直接三维偏序就好了。

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 using namespace std;
  7 struct node{
  8     long long x,y,z,s;
  9 }    a[100005],b[100005],bb[100005],c[100005],cc[100005];
 10 long long n,m;
 11 long long bit[100005],to[100005],sum[100005];
 12 inline void add(long long x){
 13     for(long long i=x;i<=n;i+=(i&-i)){
 14         bit[i]++;
 15     }
 16 }
 17 inline long long query(long long x){
 18     long long ret=0;
 19     for(long long i=x;i;i-=(i&-i)){
 20         ret+=bit[i];
 21     }
 22     return ret;
 23 }
 24 inline void clean(long long x){
 25     for(long long i=x;i<=n;i+=(i&-i)){
 26         bit[i]=0;
 27     }
 28 }
 29 inline bool cmp(node X,node Y){
 30     return X.x<Y.x;
 31 }
 32 inline void merge1(long long l,long long r){
 33     if(l==r)    return;
 34     long long mid=(l+r)>>1,pos=0;
 35     merge1(l,mid);merge1(mid+1,r);
 36     long long L=l,R=mid+1;
 37     while(R<=r){
 38         while(L<=mid && (b[L].y>b[R].y)){
 39             bb[++pos]=b[L++];
 40             add(bb[pos].z);
 41         }
 42         bb[++pos]=b[R++];
 43         bb[pos].s+=query(bb[pos].z);
 44     }
 45     for(long long i=L;i<=mid;i++){
 46         bb[++pos]=b[i];
 47     }
 48     pos=0;
 49     for(long long i=l;i<=r;i++){
 50         b[i]=bb[++pos];
 51         clean(b[i].z);
 52     }
 53 }
 54 inline void merge2(long long l,long long r){
 55     if(l==r)    return;
 56     long long mid=(l+r)>>1,pos=0;
 57     merge2(l,mid);merge2(mid+1,r);
 58     long long L=l,R=mid+1;
 59     while(R<=r){
 60         while(L<=mid && (c[L].y<c[R].y)){
 61             cc[++pos]=c[L++];
 62             add(cc[pos].z);
 63         }
 64         cc[++pos]=c[R++];
 65         cc[pos].s+=query(n)-query(cc[pos].z);
 66     }
 67     for(long long i=L;i<=mid;i++){
 68         cc[++pos]=c[i];
 69     }
 70     pos=0;
 71     for(long long i=l;i<=r;i++){
 72         c[i]=cc[++pos];
 73         clean(c[i].z);
 74     }
 75 }
 76 int main(){
 77     long long pos,x,ans=0;
 78     scanf("%lld%lld",&n,&m);
 79     for(long long i=1;i<=n;i++){
 80         scanf("%d",&a[i].y);
 81         a[i].z=i;
 82         to[a[i].y]=i;
 83     }
 84     pos=n;
 85     for(long long i=1;i<=m;i++){
 86         scanf("%lld",&x);
 87         a[to[x]].x=pos--;
 88     }
 89     pos=0;
 90     for(long long i=1;i<=n;i++){
 91         if(!a[i].x)    a[i].x=++pos;
 92     }
 93     sort(a+1,a+n+1,cmp);
 94     pos=0;
 95     for(long long i=1;i<=n;i++){
 96         b[i]=a[i];
 97         c[i]=a[i];
 98     }
 99     merge1(1,n);
100     merge2(1,n);
101     sort(b+1,b+n+1,cmp);
102     sort(c+1,c+n+1,cmp);
103     for(long long i=1;i<=n-m;i++)
104         ans+=b[i].s+c[i].s;
105     pos=m;
106     for(long long i=n-m+1;i<=n;i++){
107         sum[pos--]=ans+c[i].s+b[i].s;
108         ans+=c[i].s+b[i].s;
109     }
110     for(long long i=1;i<=m;i++){
111         printf("%lld\n",sum[i]);
112     }
113     return 0;
114 }

 

posted @ 2017-11-29 22:37  LittleOrange  阅读(183)  评论(0编辑  收藏  举报