BZOJ3295[CQOI2011]动态逆序对(CDQ分治)

第一个不看题解A了的CDQ题目QwQ

Time Limit: 10 Sec  Memory Limit: 128 MB

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

Sample Output

5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。


解析:

1.逆序对个数是满足a[i]>a[j]&&i<j的(i, j)个数。

2.题目说删除,不好处理,我们倒过来当成添加元素,统计每次添加元素会增加多少个逆序对,答案为依次累加的和。

3.一个操作除了可以用顺序(也可理解为时间)和位置表示,为了方便还可扩展为顺序(时间)、位置、数值三个指标表示,那么对于(pos[i],a[i],time[i]),增加的逆序对个数等于满足image 的j的个数(注意time的大小关系,因为是倒过来,时间大的先添加)。

4.没有删完的情况,剩下的部分人为地随便顺序删掉就行,补齐n个操作。

5.答案会爆int。

然后就可以先对time排序,分两半,右边加进树状数组,更新左边的答案,再递归处理两半。

我的代码很乱很乱很乱

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 struct Query
  8 {
  9 	int id, pos, val;
 10 }q[100010], tmp[100010];
 11 
 12 int n, m, cnt, pos[100010], arr[100010], tree[100010];
 13 long long ans[100010];
 14 
 15 void Add(int, int);
 16 int query(int);
 17 void CDQ(int, int);
 18 bool cmp(Query, Query);
 19 
 20 int main()
 21 {
 22 	scanf("%d%d", &n, &m);
 23 	for(int i = 0; i < n; i++)
 24 	{
 25 		scanf("%d", arr + i);
 26 		pos[arr[i]] = i;
 27 	}
 28 	for(cnt = 0; cnt < m; cnt++)
 29 	{
 30 		int t;
 31 		scanf("%d", &t);
 32 		q[cnt].pos = pos[t];
 33 		q[cnt].val = t;
 34 		q[cnt].id = cnt;
 35 		arr[pos[t]] = 0;
 36 	}
 37 	for(int i = 0; i < n; i++)
 38 		if(arr[i])
 39 		{
 40 			q[cnt].pos = i;
 41 			q[cnt].val = arr[i];
 42 			q[cnt].id = cnt;
 43 			cnt++;
 44 		}
 45 	sort(q, q + n);
 46 	CDQ(0, n - 1);
 47 	for(int i = n - 1; i >= 0; i--)
 48 		ans[i] += ans[i + 1];
 49 	for(int i = 0; i < m; i++)
 50 		printf("%lld\n", ans[i]);
 51 
 52 	return 0;
 53 }
 54 void Add(int _pos, int val)
 55 {
 56 	for(int i = _pos; i <= n; i += (i & (-i)))
 57 		tree[i] += val;
 58 }
 59 
 60 int query(int _pos)
 61 {
 62 	int res = 0;
 63 	for(int i = _pos; i > 0; i -= (i & (-i)))
 64 		res += tree[i];
 65 	return res;
 66 }
 67 
 68 bool operator <(Query a, Query b)
 69 {
 70 	return a.pos < b.pos;
 71 }
 72 
 73 void CDQ(int l, int r)
 74 {
 75 	if(l == r) return;
 76 	int mid = (l + r) >> 1;
 77 	for(int i = l; i <= r; i++)
 78 		if(q[i].id <= mid) ans[q[i].id] += (long long)query(n) - query(q[i].val);
 79 		else Add(q[i].val, 1);
 80 	for(int i = l; i <= r; i++)
 81 		if(q[i].id > mid)
 82 			Add(q[i].val, -1);
 83 	for(int i = r; i >= l; i--)
 84 		if(q[i].id <= mid) ans[q[i].id] += (long long)query(q[i].val);
 85 		else Add(q[i].val, 1);
 86 	for(int i = l; i <= r; i++)
 87 		if(q[i].id > mid)
 88 			Add(q[i].val, -1);
 89 	int l1 = l, l2 = mid + 1;
 90 	for(int i = l; i <= r; i++)
 91 		if(q[i].id <= mid) tmp[l1++] = q[i];
 92 		else tmp[l2++] = q[i];
 93 	for(int i = l; i <= r; i++)
 94 		q[i] = tmp[i];
 95 	CDQ(l, mid);
 96 	CDQ(mid + 1, r);
 97 }
 98 //Rhein_E

这是一个悲伤的故事。。。。image

猜你喜欢

转载自www.cnblogs.com/Rhein-E/p/9498494.html