对于二维偏序,为普通的求逆序对,只需要先排序一遍,然后树状数组或双指针即可
而三位偏序甚至更高,则需要用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;
}
标签:偏序,rua,return,int,分治,mid,算法,CDQ,数组
From: https://www.cnblogs.com/MafuyuQWQ/p/18420327