[CQOI2011]动态逆序对
时间限制:2 s 内存限制:128 MB
【题目描述】
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
【输入格式】
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
【输出格式】
输出包含m行,依次为删除每个元素之前,逆序对的个数。
【样例输入】
5 4 1 5 3 4 2 5 1 4 2
【样例输出】
5 2 2 1
样例解释 (1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。
【提示】
N<=100000 M<=50000
【来源】
【题目来源】
三维的cdq分治,对每一个点额外记录一个变量来表示他的删除时间,为了后面树状数组的操作方便,我们反过来维护,即维护其“插入时间”,看做是由最终状态插入得到的,那么问题就转换成了,每插入一个数,就求出这个数和早于他插入的数字构成的逆序对数。这道题需要同时计算左边对右边的影响和右边对左边的影响,但是没被删除的也就是我代码中插入时间为1的那些数字,他们所构成的逆序对数会被计算两次,所以要除二,那么最终求得的数组就表示的每次插入数字所形成的逆序对数,求一下前缀和输出即可。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int maxn=1e5+10; 5 int n,m,hs[maxn],s[maxn]; 6 ll ans[maxn]; 7 int read(){ 8 int a=0; 9 char ch=getchar(); 10 while(!(ch<=‘9‘&&ch>=‘0‘))ch=getchar(); 11 while(ch<=‘9‘&&ch>=‘0‘){ 12 a=(a<<1)+(a<<3)+(ch^‘0‘); 13 ch=getchar(); 14 } 15 return a; 16 } 17 struct number{ 18 int val,tim; 19 }q[maxn],tmp[maxn]; 20 int lowbit(int x){ 21 return x&(-x); 22 } 23 void add(int x){ 24 for(int i=x;i<=m+1;i+=lowbit(i))s[i]++; 25 } 26 int sum(int x){ 27 int t=0; 28 for(int i=x;i;i-=lowbit(i))t+=s[i]; 29 return t; 30 } 31 void clear(int x){ 32 for(int i=x;i<=m+1;i+=lowbit(i)){ 33 if(s[i])s[i]=0; 34 else break; 35 } 36 } 37 void cdq(int l,int r){ 38 if(l==r)return ; 39 int mid=(l+r)>>1; 40 cdq(l,mid);cdq(mid+1,r); 41 int o,p1=l,p2=mid+1; 42 while(p1<=mid&&p2<=r){ 43 if(q[p1].val>q[p2].val){ 44 add(q[p1].tim); 45 p1++; 46 } 47 else { 48 ans[q[p2].tim]+=sum(q[p2].tim); 49 p2++; 50 } 51 } 52 while(p2<=r){ 53 ans[q[p2].tim]+=sum(q[p2].tim); 54 p2++; 55 } 56 for(int i=l;i<=p1;i++)clear(q[i].tim); 57 p1=mid,p2=r,o=r+1; 58 while(p1>=l&&p2>=mid+1){ 59 if(q[p1].val>q[p2].val){ 60 add(q[p2].tim); 61 tmp[--o]=q[p2--]; 62 } 63 else { 64 ans[q[p1].tim]+=sum(q[p1].tim); 65 tmp[--o]=q[p1--]; 66 } 67 } 68 while(p1>=l){ 69 ans[q[p1].tim]+=sum(q[p1].tim); 70 tmp[--o]=q[p1--]; 71 } 72 while(p2>=mid+1)tmp[--o]=q[p2--]; 73 for(int i=l;i<=r;i++){ 74 clear(q[i].tim); 75 q[i]=tmp[i]; 76 } 77 } 78 void out(ll x){ 79 if(x/10)out(x/10); 80 putchar(‘0‘+x%10); 81 } 82 int main() 83 { 84 freopen("inverse.in","r",stdin); 85 freopen("inverse.out","w",stdout); 86 n=read();m=read(); 87 for(int i=1;i<=n;i++){ 88 q[i].val=read(); 89 hs[q[i].val]=i; 90 q[i].tim=1; 91 } 92 for(int i=1;i<=m;i++){ 93 int x; 94 x=read(); 95 q[hs[x]].tim=m-i+2; 96 } 97 cdq(1,n); 98 ans[1]/=2; 99 for(int i=2;i<=m+1;i++)ans[i]+=ans[i-1]; 100 for(int i=m+1;i>=2;i--){ 101 out(ans[i]); 102 putchar(‘\n‘); 103 } 104 return 0; 105 }