luogu P3157 [CQOI2011]动态逆序对(CDQ分治)

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

题解

我们发现一个数的贡献,就是就是t'<t(删除时间),xb'<xb(下标),w'>w(权值)的数的数量和t'>t,xb'>xb,w'<w的数的数量之和。

这就是一个三维偏序类型的题,所以做两遍CDQ分治分别的到这两种贡献。最后用总逆序对数减去就好了。

1A真开心。。。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cmath>
  6 using namespace std;
  7 const long long N=100100;
  8 long long n,m,a[N],b[N],tmp,tr[N],ans[N],book[N],ma[N],tot;
  9 struct query{
 10     long long id,xb,w;
 11 }q[N],c[N];
 12 bool cmp(query a,query b){
 13     return a.id>b.id;
 14 }
 15 void gb(long long l,long long r){
 16     if(l==r)return;
 17     long long mid=(l+r)>>1;
 18     gb(l,mid);
 19     gb(mid+1,r);
 20     long long ll=l;
 21     long long lr=mid+1;
 22     long long cnt=0;
 23     while(ll<=mid&&lr<=r){
 24         cnt++;
 25         if(a[ll]<a[lr]){
 26             b[cnt]=a[ll++];
 27         }
 28         else{
 29             b[cnt]=a[lr++];
 30             tmp+=mid-ll+1;
 31         }
 32     }
 33     while(ll<=mid)b[++cnt]=a[ll++];
 34     while(lr<=r)b[++cnt]=a[lr++];
 35     for(long long i=l;i<=r;i++){
 36         a[i]=b[i-l+1];
 37     }
 38 }
 39 long long lowbit(long long x){
 40     return x&-x;
 41 }
 42 void add(long long x,long long w){
 43     for(long long i=x;i<=n;i+=lowbit(i)){
 44         tr[i]+=w;
 45     }
 46 }
 47 long long getsum(long long x){
 48     long long ans=0;
 49     for(long long i=x;i>=1;i-=lowbit(i)){
 50         ans+=tr[i];
 51     }
 52     return ans;
 53 }
 54 void cdq(long long l,long long r){
 55     if(l==r)return;
 56     long long mid=(l+r)>>1;
 57     cdq(l,mid);cdq(mid+1,r);
 58     long long ll=l;long long rl=mid+1;long long now=0;
 59     while(ll<=mid&&rl<=r){
 60         if(q[ll].xb<q[rl].xb){
 61             add(q[ll].w,1);
 62             c[++now]=q[ll++];
 63         }
 64         else{
 65             ans[q[rl].id]+=getsum(n)-getsum(q[rl].w);
 66             c[++now]=q[rl++];
 67         }
 68     }
 69     while(ll<=mid){
 70         add(q[ll].w,1);
 71         c[++now]=q[ll++];
 72     }
 73     while(rl<=r){
 74         ans[q[rl].id]+=getsum(n)-getsum(q[rl].w);
 75         c[++now]=q[rl++];
 76     }
 77     for(long long i=l;i<=mid;i++)add(q[i].w,-1);    
 78     for(long long i=l;i<=r;i++)q[i]=c[i-l+1];
 79 }
 80 void CDQ(long long l,long long r){
 81     if(l==r)return;
 82     long long mid=(l+r)>>1;
 83     CDQ(l,mid);CDQ(mid+1,r);
 84     long long ll=l;long long rl=mid+1;long long now=0;
 85     while(ll<=mid&&rl<=r){
 86         if(q[ll].xb>q[rl].xb){
 87             add(q[ll].w,1);
 88             c[++now]=q[ll++];
 89         }
 90         else{
 91             ans[q[rl].id]+=getsum(q[rl].w);
 92             c[++now]=q[rl++];
 93         }
 94     }
 95     while(ll<=mid){
 96         add(q[ll].w,1);
 97         c[++now]=q[ll++];
 98     }
 99     while(rl<=r){
100         ans[q[rl].id]+=getsum(q[rl].w);
101         c[++now]=q[rl++];
102     }
103     for(long long i=l;i<=mid;i++)add(q[i].w,-1);
104     for(long long i=l;i<=r;i++)q[i]=c[i-l+1];
105 }
106 int main(){
107     scanf("%lld%lld",&n,&m);
108     for(long long i=1;i<=n;i++){
109         scanf("%lld",&a[i]);
110         ma[a[i]]=i;
111     }
112     for(long long i=1;i<=m;i++){
113         long long x;
114         scanf("%lld",&x);
115         q[i].id=i;q[i].xb=ma[x];q[i].w=x;
116         book[ma[x]]=1;
117     }
118     tot=m;
119     for(long long i=1;i<=n;i++){
120         if(book[i]==0){
121             q[++tot].id=m+1;q[tot].xb=i;q[tot].w=a[i];
122         }
123     }
124     sort(q+1,q+n+1,cmp);
125     cdq(1,n);
126     sort(q+1,q+n+1,cmp);
127     CDQ(1,n);
128     gb(1,n);
129     for(long long i=1;i<=m;i++){
130         printf("%lld\n",tmp);
131         tmp-=ans[i];
132     }
133     return 0;
134 }

 

posted @ 2018-08-11 16:24  Xu-daxia  阅读(169)  评论(0编辑  收藏  举报