陌上花开,可缓缓归矣
三维偏序
可以使用\(CDQ\)分治来解决
首先考虑分治
对于要处理的区间,按照\(x\)排序,保持一维关系,分成前后两块,按\(y\)排序,那么前后两块保证的是前面那块的\(x\)小于后面那块,对于\(z\)用数据结构(树状数组好了)维护,用前面那段更新后面那段就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 100005
#define lowbit(x) (x & -x)
struct P{
ll x,y,z,id;
}e[N];
ll ans[N],unq[N],f[N];
ll t[N * 2];
ll n,k;
void add(ll x,ll p){
for(int i = x;i <= k;i += lowbit(i))
t[i] += p;
}
int get(ll x){
ll ans = 0;
for(int i = x;i;i -= lowbit(i))
ans += t[i];
return ans;
}
bool cmp(P t,P s){
if(t.x != s.x)
return t.x < s.x;
if(t.y != s.y)
return t.y < s.y;
return t.z < s.z;
}
bool cmp1(P t,P s){
if(t.y != s.y)
return t.y < s.y;
if(t.z != s.z)
return t.z < s.z;
return t.x < s.x;
}
void cdq(ll l,ll r){
if(l == r)
return;
int mid = (l + r) >> 1;
cdq(l,mid),cdq(mid + 1,r);
std::sort(e + l,e + r + 1,cmp1);
for(int i = l;i <= r;++i)
if(e[i].x <= mid)
add(e[i].z,1);
else
ans[e[i].id] += get(e[i].z);
for(int i = l;i <= r;++i){
if(e[i].x <= mid)
add(e[i].z,-1);
// printf("%lld %lld\n",e[i].x,ans[e[i].id]);
}
}
int main(){
scanf("%lld%lld",&n,&k);
for(int i = 1;i <= n;++i)
scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].z),e[i].id = i;
std::sort(e + 1,e + n + 1,cmp);
for(int i = 1,j;i <= n;){
j = i + 1;
while(j <= n && e[j].x == e[i].x && e[j].y == e[i].y && e[j].z == e[i].z)
j ++ ;
while(i < j)
unq[e[i].id] = e[j - 1].id,i ++ ;
}
for(int i = 1;i <= n;++i)
e[i].x = i;
cdq(1,n);
for(int i = 1;i <= n;++i)
f[ans[unq[e[i].id]]] ++ ;
for(int i = 0;i < n;++i)
printf("%lld\n",f[i]);
}