luogu P3810(kd-tree)

题目链接

题意:三维偏序

kd-tree解法

首先暴力的kd-tree是3维的,过不去.所以需要先把一维排序,然后对剩下的2维建kd-tree

这个kd-tree是在线插入的,所以需要定时重构,然后重构的次数比较玄学,由于kd-tree本身复杂度 O ( n n ) O(n\sqrt n) 左右,所以块长一开始设成了 n \sqrt 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;
}

发布了62 篇原创文章 · 获赞 1 · 访问量 1003

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103762336