算法学习-CDQ分治

对于二维偏序,为普通的求逆序对,只需要先排序一遍,然后树状数组或双指针即可
而三位偏序甚至更高,则需要用CDQ分治,简单来说,就是将树状数组和双指针结合
操作步骤如下:

  • 1.开始将数组按第一维排序,保证满足x性质
  • 2.在归并中,将左右分别按y排序,因为开始以x排序,所以保证了正确性,保证贡献从左到右
  • 3.相当于用树状数组处理二维偏序,再用双指针合并左右两部分数组即可
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 200010;

int n, k;
struct rua
{
	int x, y, z;
	int res, cnt;
} a[N];
int tr[N], res[N];

bool check(int x, int y)
{
	return (a[x].x == a[y].x && a[x].y == a[y].y && a[x].z == a[y].z);
}

bool cmpx(rua x, rua y)
{
	if (x.x != y.x) return x.x < y.x;
	else if (x.y != y.y) return x.y < y.y;
	return x.z < y.z;
}

bool cmpy(rua x, rua y)
{
	if (x.y != y.y) return x.y < y.y;
	return x.z < y.z;
}

int lowbit(int x)
{
	return x & -x;
}

void update(int x, int v)
{
	for (int i = x; i <= k; i += lowbit(i)) tr[i] += v;
}

int query(int x)
{
	int res = 0;
	for (int i = x; i; i -= lowbit(i)) res += tr[i];
	return res;
}

void solve(int l, int r)
{
	if (l == r) return;
	int mid = l + r >> 1;
	solve(l, mid), solve(mid + 1, r);
	sort(a + l, a + mid + 1, cmpy);
	sort(a + mid + 1, a + r + 1, cmpy);
	int i = mid + 1, j = l;
	while (i <= r)
	{
		while (a[j].y <= a[i].y && j <= mid) update(a[j].z, a[j].cnt), j ++ ;
		a[i].res += query(a[i].z);
		i ++ ;
	}
	for (int i = l; i < j; i ++ ) update(a[i].z, -a[i].cnt);
}

signed main()
{
	cin >> n >> k;
	for (int i = 1; i <= n; i ++ ) cin >> a[i].x >> a[i].y >> a[i].z;
	
	sort(a + 1, a + 1 + n, cmpx);
//	for (int i = 1; i <= n; i ++ ) cout << a[i].x << ' ' << a[i].y << ' ' << a[i].z << '\n';
	int cnt = 0;
	for (int i = 1; i <= n; i ++ )
	{
		int j = i + 1;
		while (check(i, j)) j ++ ;
		j -- ;
		a[ ++ cnt] = {a[i].x, a[i].y, a[i].z, 0, j - i + 1};
		i = j;
	}
//	for (int i = 1; i <= n; i ++ )
//		cout << a[i].cnt << ' ';
//	cout << '\n';
	
	solve(1, n);
	
	for (int i = 1; i <= n; i ++ ) res[a[i].res + a[i].cnt - 1] += a[i].cnt;
	
	for (int i = 0; i < n; i ++ ) cout << res[i] << '\n';
	
	return 0;
}
posted @   MafuyuQWQ  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示