[BZOJ3295][Cqoi2011]动态逆序对
Posted wls001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3295][Cqoi2011]动态逆序对相关的知识,希望对你有一定的参考价值。
3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5276 Solved: 1783
[Submit][Status][Discuss]
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
样例解释
(1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。
2
2
1
样例解释
(1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。
HINT
N<=100000 M<=50000
cdq分治裸题。
首先我们把删除改为倒序插入,对于每一个操作,我们记录三元组(x,y,z)表示位置为x数值为y操作时间为z。此时,我们要求对于每一个(x,y,z)的z0<z&&x0<x&&y0》y。
我们首先考虑对于z从小到大排序,这样,我们就能忽略z的影响。此时,我们要求x0<x&&y0>y的组数。
现在我们开始分治。
首先对于区间(l,r),区间(l,mid)中所有元素的z都小于(mid+1,r)中所有元素的z,所以我们考虑(l,mid)中的修改对(mid+1,r)中的每个元素的影响。
现在我们对区间(l,mid)中的所有元素打上标记,使其成为修改操作,对于区间(mid+1,r)中的所有元素打上标记,使其成为询问操作。
我们对区间(l,r)以x为第一关键字排序,这样,我们要求的就是a[i].y<a[j].y(i>j) a[i].y>a[j].y(i<j)的个数,可以用树状数组维护。
处理完区间(l,r),我们可以分治处理(l,mid)(mid+1,r)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 int n,m; 9 struct data 10 { 11 int x,y,z; 12 int flag; 13 }a[100008],b[100008]; 14 int w[100008]; 15 bool cmp1(data s1,data s2){return s1.z<s2.z;} 16 bool cmp2(data s1,data s2){return s1.x<s2.x;} 17 int tre[100008]; 18 long long ans[100008]; 19 int lowbit(int x){return x&(-x);} 20 void update(int x,int ad){for(int i=x;i<=n;i+=lowbit(i)) tre[i]+=ad;} 21 int query(int x) 22 { 23 int re=0; 24 for(int i=x;i>0;i-=lowbit(i)) re+=tre[i]; 25 return re; 26 } 27 void cdq(int l,int r) 28 { 29 if(l>=r) return; 30 int mid=(l+r)>>1; 31 int cnt=0; 32 for(int i=l;i<=r;i++) 33 { 34 if(i<=mid){b[++cnt]=a[i];b[cnt].flag=0;} 35 else {b[++cnt]=a[i];b[cnt].flag=1;} 36 } 37 sort(b+1,b+cnt+1,cmp2); 38 for(int i=1;i<=cnt;i++) 39 { 40 if(!b[i].flag) update(b[i].y,1); 41 else ans[b[i].z]+=(long long)(query(n)-query(b[i].y)); 42 } 43 for(int i=1;i<=cnt;i++) if(!b[i].flag) update(b[i].y,-1); 44 for(int i=cnt;i>=1;i--) 45 { 46 if(!b[i].flag) update(b[i].y,1); 47 else ans[b[i].z]+=(long long)query(b[i].y); 48 } 49 for(int i=1;i<=cnt;i++) if(!b[i].flag) update(b[i].y,-1); 50 cdq(l,mid); cdq(mid+1,r); 51 } 52 int main() 53 { 54 scanf("%d%d",&n,&m); 55 int c=n; 56 for(int i=1;i<=n;i++) 57 { 58 a[i].x=i;scanf("%d",&a[i].y);w[a[i].y]=i; 59 } 60 for(int i=1;i<=m;i++) 61 { 62 int t; 63 scanf("%d",&t); 64 a[w[t]].z=c--; 65 } 66 for(int i=n;i>=1;i--) if(!a[i].z) a[i].z=c--; 67 sort(a+1,a+n+1,cmp1); 68 cdq(1,n); 69 for(int i=1;i<=n;i++) ans[i]+=ans[i-1]; 70 for(int i=n;i>=n-m+1;i--) printf("%lld\n",ans[i]); 71 }
以上是关于[BZOJ3295][Cqoi2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章