1. 程式人生 > >luogu P3157 [CQOI2011]動態逆序對(CDQ分治)

luogu P3157 [CQOI2011]動態逆序對(CDQ分治)

include 兩種 包含 之間 sum 輸入格式 貢獻 += 逆序對

題目描述

對於序列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 }

luogu P3157 [CQOI2011]動態逆序對(CDQ分治)