luogu P3157 [CQOI2011]动态逆序对(CDQ分治)
Posted xu-daxia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ",tmp); 131 tmp-=ans[i]; 132 } 133 return 0; 134 }
以上是关于luogu P3157 [CQOI2011]动态逆序对(CDQ分治)的主要内容,如果未能解决你的问题,请参考以下文章
luogu P3157 [CQOI2011]动态逆序对(CDQ分治)