题意:三维偏序
kd-tree解法
首先暴力的kd-tree是3维的,过不去.所以需要先把一维排序,然后对剩下的2维建kd-tree
这个kd-tree是在线插入的,所以需要定时重构,然后重构的次数比较玄学,由于kd-tree本身复杂度 O ( n n ) O(n\sqrt n) O(nn)左右,所以块长一开始设成了 n \sqrt n n,但是过不去(甚至没有3维的kd-tree暴力快),后来把块长*25,就卡过了.
注意插入的时候需要把排序的那一维全部相等的元素一起插入进去(或者插入完了以后一起查询),如果一个一个插入,会漏解,可能后插入的点可以被先插入的点覆盖.
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
inline int read(){
char c=getchar();int t=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,k;
struct node{
int a[3];
}a[maxn],b[maxn];
int opt;
bool cmp(node a,node b){
return a.a[opt]<b.a[opt];
}
int ans,tim;
#define lc ch[x][0]
#define rc ch[x][1]
struct tree{
int ch[maxn][2],mx[maxn][2],mn[maxn][2],cnt,rt,sz[maxn],dep[maxn];
node p[maxn];
inline void pushup(int x){
sz[x]=1;
for(int i=0;i<2;i++)mn[x][i]=mx[x][i]=p[x].a[i];
if(lc){
for(int i=0;i<2;i++){mn[x][i]=min(mn[x][i],mn[lc][i]);mx[x][i]=max(mx[x][i],mx[lc][i]);}
sz[x]+=sz[lc];
}
if(rc){
for(int i=0;i<2;i++){mn[x][i]=min(mn[x][i],mn[rc][i]);mx[x][i]=max(mx[x][i],mx[rc][i]);}
sz[x]+=sz[rc];
}
}
void insert(int &x,node q,int fa){
//printf("%d %d %d\n",x,fa,cnt);
if(!x){cnt++;x=cnt;dep[x]=dep[fa]+1;p[x]=q;pushup(x);return ;}
opt=dep[x]&1;
if(p[x].a[opt]<q.a[opt]){insert(rc,q,x);}
else insert(lc,q,x);
pushup(x);
}
void reset(int &x){
if(lc)reset(lc);
if(rc)reset(rc);
for(int i=0;i<2;i++){mn[x][i]=mx[x][i]=p[x].a[i]=0;}
sz[x]=0;dep[x]=0;ch[x][0]=ch[x][1]=0;x=0;
}
void rs(){cnt=0;}
void build(int &x,int l,int r,int fa){if(l>r)return ;
if(!x){
cnt++;
x=cnt;dep[x]=dep[fa]+1;//printf("%d %d %d %d\n",x,l,r,fa);
}
opt=dep[x]&1;int mid=(l+r)>>1;
// printf("%d\n",mid);
nth_element(a+l,a+mid,a+r+1,cmp);p[x]=a[mid];
build(lc,l,mid-1,x);build(rc,mid+1,r,x);
pushup(x);
}
void query(int x,node q){
if(!x)return ;
int flag=1;
for(int i=0;i<2;i++){if(p[x].a[i]>q.a[i]){flag=0;break;}}
if(flag)ans++;
flag=1;
for(int i=0;i<2;i++){if(mx[lc][i]>q.a[i]){flag=0;break;}}
if(flag)ans+=sz[lc];
else{
flag=1;
for(int i=0;i<2;i++){if(mn[lc][i]>q.a[i]){flag=0;break;}}
if(flag)query(lc,q);
}
flag=1;
for(int i=0;i<2;i++){if(mx[rc][i]>q.a[i]){flag=0;break;}}
if(flag)ans+=sz[rc];
else{
flag=1;
for(int i=0;i<2;i++){if(mn[rc][i]>q.a[i]){flag=0;break;}}
if(flag)query(rc,q);
}
}
}t;
int ton[maxn];
bool cmp1(node a,node b){
return a.a[2]<b.a[2];
}
int main(){
//freopen("3810.in","r",stdin);
//freopen("3810.out","w",stdout);
n=read(),k=read();
for(int i=1;i<=n;i++){
a[i].a[0]=read(),a[i].a[1]=read(),a[i].a[2]=read();
}
tim=25*sqrt(n);
sort(a+1,a+1+n,cmp1);
for(int i=1;i<=n;i++)b[i]=a[i];
int lst=1;
for(int i=1;i<=n;i++){
//printf("%d %d %d %d\n",a[i].a[0],a[i].a[1],a[i].a[2],i);
t.insert(t.rt,a[i],0);
if(i%tim==0){
t.reset(t.rt);t.rs();
t.build(t.rt,1,i,0);
}
if(b[i].a[2]!=b[i+1].a[2]){
for(int j=lst;j<=i;j++){
ans=0;t.query(t.rt,b[j]);ans--;
// printf("%d %d %d %d\n",b[j].a[0],b[j].a[1],b[j].a[2],j);
ton[ans]++;
}
lst=i+1;
}
}
for(int i=0;i<n;i++){
printf("%d\n",ton[i]);
}
return 0;
}