BZOJ3295 [Cqoi2011]动态逆序对 —— CDQ分治
题目链接:https://vjudge.net/problem/HYSBZ-3295
3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6517 Solved: 2295
[Submit][Status][Discuss]
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删
除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
以下n行每行包含一个1到n之间的正整数,即初始排列。
以下m行每行一个正整数,依次为每次删除的元素。
N<=100000 M<=50000
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)。
题解:
1.最核心的问题是:删除当前位置的数,会造成多少对逆序对的减少。
2.要统计删除当前数会造成多少对逆序对的减少,即需要统计:前面比它大的数的个数 + 后面比它小的数的个数 (前提是这些数没有被删除)。
3.由于题目还存在动态删除,则再为每个位置添加一个标志:Di,表明它是第几个被删除的。加上这个限制,就是一个三维偏序问题了。
4.以j为统计对象,sum[j]为删除位置j的数,所减少的逆序对。sum[j] = sum (i<j 且 Ai>Aj 且 Di>Dj)+ (j<i 且 Aj>Ai 且 Di>Dj)
5.得到sum数组之后,即知道删除当前位置的数,会造成多少对逆序对的减少。那么再算出初始的逆序对(不带删除,即二维偏序)即可。
写法一:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 1e5+100; 18 19 struct node 20 { 21 int x, y, z; 22 }; 23 node a[MAXN], b[MAXN], tmp[MAXN]; 24 25 int n, m, c[MAXN]; 26 int lowbit(int x) {return x&(-x);} 27 void add(int x, int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;} 28 int query(int x) {int ret=0; for(int i=x;i>0;i-=lowbit(i))ret+=c[i]; return ret;} 29 30 int sum[MAXN], type; 31 void CDQ(int l, int r) 32 { 33 if(l==r) return; 34 35 int mid = (l+r)>>1; 36 CDQ(l, mid); CDQ(mid+1, r); 37 int p1 = l, p2 = mid+1; 38 for(int i = l; i<=r; i++) 39 { 40 if(p2>r||(p1<=mid&&a[p1].y>=a[p2].y)) b[i] = a[p1++]; 41 else b[i] = a[p2++]; 42 } 43 int cnt = 0; //按删除顺序逆序排序了,所以先出现的更后删除 44 for(int i = l; i<=r; i++) //统计前面比它小的 45 { 46 a[i] = b[i]; 47 if(a[i].x<=mid) add(a[i].z, 1), cnt++; 48 else if(a[i].y!=INF) sum[a[i].y] += cnt-query(a[i].z); 49 } 50 for(int i = l; i<=r; i++) 51 if(a[i].x<=mid) add(a[i].z, -1); 52 53 for(int i = l; i<=r; i++) //统计后面比它大的 54 { 55 a[i] = b[i]; 56 if(a[i].x>mid) add(a[i].z, 1); 57 else if(a[i].y!=INF) sum[a[i].y] += query(a[i].z-1); 58 } 59 for(int i = l; i<=r; i++) 60 if(a[i].x>mid) add(a[i].z, -1); 61 } 62 63 int M[MAXN]; 64 int main() 65 { 66 while(scanf("%d%d", &n,&m)!=EOF) 67 { 68 for(int i = 1; i<=n; i++) 69 { 70 scanf("%d", &a[i].z); 71 M[a[i].z] = i; 72 a[i].x = i; a[i].y = INF; 73 } 74 for(int i = 1; i<=m; i++) 75 { 76 int del; 77 scanf("%d", &del); 78 a[M[del]].y = i; 79 } 80 81 LL ans = 0; 82 memset(c, 0, sizeof(c)); 83 for(int i = 1; i<=n; i++) 84 { 85 ans += (i-1)-query(a[i].z); 86 add(a[i].z, 1); 87 } 88 89 memset(c, 0, sizeof(c)); 90 memset(sum, 0, sizeof(sum)); 91 CDQ(1,n); 92 93 printf("%lld\n", ans); 94 for(int i = 1; i<m; i++) 95 { 96 ans -= sum[i]; 97 printf("%lld\n", ans); 98 } 99 } 100 }
写法二:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 1e5+100; 18 19 struct node 20 { 21 int x, y, z; 22 }; 23 node a[MAXN], b[MAXN]; 24 25 int n, m, c[MAXN]; 26 int lowbit(int x) {return x&(-x);} 27 void add(int x, int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;} 28 int query(int x) {int ret=0; for(int i=x;i>0;i-=lowbit(i))ret+=c[i]; return ret;} 29 30 int sum[MAXN], type; 31 void CDQ(int l, int r) 32 { 33 if(l==r) return; 34 35 int mid = (l+r)>>1; 36 CDQ(l, mid); CDQ(mid+1, r); 37 int p1 = l, p2 = mid+1; 38 for(int i = l; i<=r; i++) 39 { 40 if(p2>r||(p1<=mid&&a[p1].y>=a[p2].y)) b[i] = a[p1++]; 41 else b[i] = a[p2++]; 42 } 43 int cnt = 0; 44 for(int i = l; i<=r; i++) 45 { 46 a[i] = b[i]; 47 if(a[i].x<=mid) add(a[i].z, 1), cnt++; 48 else if(a[i].y!=INF) 49 { 50 if(type) sum[a[i].y] += cnt-query(a[i].z); 51 else sum[a[i].y] += query(a[i].z-1); 52 } 53 } 54 for(int i = l; i<=r; i++) 55 if(a[i].x<=mid) add(a[i].z, -1); 56 } 57 58 node tmp[MAXN]; 59 int M[MAXN]; 60 int main() 61 { 62 while(scanf("%d%d", &n,&m)!=EOF) 63 { 64 for(int i = 1; i<=n; i++) 65 { 66 scanf("%d", &a[i].z); 67 M[a[i].z] = i; 68 a[i].y = INF; 69 } 70 for(int i = 1; i<=m; i++) 71 { 72 int del; 73 scanf("%d", &del); 74 a[M[del]].y = i; 75 } 76 77 LL ans = 0; 78 memset(c, 0, sizeof(c)); 79 for(int i = 1; i<=n; i++) 80 { 81 ans += (i-1)-query(a[i].z); 82 add(a[i].z, 1); 83 } 84 85 memcpy(tmp, a, sizeof(tmp)); 86 for(int i = 1; i<=n; i++) 87 a[i].x = i; 88 memset(c, 0, sizeof(c)); 89 type = 1; 90 CDQ(1,n); 91 92 memcpy(a, tmp, sizeof(a)); 93 reverse(a+1,a+1+n); 94 for(int i = 1; i<=n; i++) 95 a[i].x = i; 96 type = 0; 97 CDQ(1,n); 98 99 printf("%lld\n", ans); 100 for(int i = 1; i<m; i++) 101 { 102 ans -= sum[i]; 103 printf("%lld\n", ans); 104 } 105 } 106 }