CDQ分治还是比较好理解的。
先按照一维排序,对一维排序的数组分治,分治的话相当于降了一维
我们只要考虑两个子区间里的数之间的大小关系,而不用考虑单个区间里面的数的影响(因为单区间里面的数已经被当成子问题解决了)
这个时候我们就可以对两个区间按照第二维排序,因为左区间的所有第一维都是小于右区间的而且我们已经不需要考虑区间内部的影响了。
现在问题转化成:两个按y排序的二维区间(y, x),右区间中每个数r[i]在左区间中存在多少个l[j]满足:r[i].y >= l[j].x && r[i].z >= r[j].z。
既然已经y有序了, 就贪心的对于每一位的r[i]找到最后一个l[j].y<= r[i].y,然后查1-i中有多少个z也是小于等于r[i].z的。
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
typedef long long ll;
const ll mod = 1e9+7;
int Case = 1;
int n, m;
struct Tree{
int c[maxn], up;
int lowbit(int x) {
return x&(-x);
}
void update(int pos, int val) {
for(int i = pos; i <= up; i += lowbit(i)) {
c[i] += val;
}
}
int query(int pos) {
int res = 0;
for(int i = pos; i >= 1; i -= lowbit(i)) {
res += c[i];
}
return res;
}
}tree;
struct node{
int x, y, z;
int cnt, res;
bool operator!=(const node a)const{
return (x != a.x) || (y != a.y) || (z != a.z);
}
}cc[maxn], t[maxn];
bool cmp1(node a, node b) {
if(a.x == b.x) {
if(a.y == b.y) {
return a.z < b.z;
}
return a.y < b.y;
}
return a.x < b.x;
}
bool cmp2(node a, node b) {
if(a.y == b.y) {
return a.z < b.z;
}
return a.y < b.y;
}
void cdq(int l, int r) {
if(l == r) return;
int mid = (l+r)/2;
cdq(l, mid);cdq(mid+1, r);
sort(cc+l, cc+1+mid, cmp2);
sort(cc+1+mid, cc+1+r, cmp2);
int li = l, lj = mid+1;
while(lj <= r) {
while(cc[li].y <= cc[lj].y && li <= mid) tree.update(cc[li].z, cc[li].cnt), li++;
cc[lj].res += tree.query(cc[lj].z);
lj++;
}
for(int i = l; i < li; i++) tree.update(cc[i].z, -cc[i].cnt);
}
int res[maxn];
void solve() {
scanf("%d%d", &n, &m);
tree.up = m;
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &t[i].x, &t[i].y, &t[i].z);
}
sort(t+1, t+1+n, cmp1);
int p = 0;
for(int i = 1; i <= n; i++) {
if(i == 1 || t[i] != cc[p]) {
cc[++p] = t[i];
}
cc[p].cnt++;
}
cdq(1, p);
for(int i = 1; i <= p; i++) {
res[cc[i].res + cc[i].cnt -1] += cc[i].cnt;
}
for(int i = 0; i < n; i++) printf("%d\n", res[i]);
return;
}
int main() {
//g++ -std=c++11 -o2 1.cpp -o f && ./f < in.txt
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
while(Case--) {
solve();
}
return 0;
}