KD-Tree

终于学会了kd树不带插入的,做了一下三维空间最近点对,记录一下板子
这道题不知道为什么不判断两坐标相同答案为0的情况,加上之后就wa

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,root,D,K=3;
struct Point{
	double d[3];
	friend bool operator < (const Point &a,const Point &b){
		if(a.d[D]!=b.d[D]) return a.d[D]<b.d[D];
		for(int i=0;i<K;i++) if(a.d[i]!=b.d[i]) return a.d[i]<b.d[i];
	}
};
Point p[N];

struct KDTree{
	#define sqr(x) ((x)*(x))
	Point p[N],minp[N],maxp[N];
	int ls[N],rs[N];
	
	void pushup(int id){
		if(ls[id]) for(int i=0;i<K;i++)
			minp[id].d[i]=min(minp[id].d[i],minp[ls[id]].d[i]),
			maxp[id].d[i]=max(maxp[id].d[i],maxp[ls[id]].d[i]);
		if(rs[id]) for(int i=0;i<K;i++)
			minp[id].d[i]=min(minp[id].d[i],minp[rs[id]].d[i]),
			maxp[id].d[i]=max(maxp[id].d[i],maxp[rs[id]].d[i]);
	}
	void build(int &id,int l,int r,int dd){
		D=dd;
		id=(l+r>>1);
		nth_element(p+l,p+id,p+r+1);
		minp[id]=p[id];maxp[id]=p[id];
		if(id!=l) build(ls[id],l,id-1,(dd+1)%K);
		if(id!=r) build(rs[id],id+1,r,(dd+1)%K);
		pushup(id);
	}
	Point A;
	double ans;
	double getdis(int id){
		double res=0;
		for(int i=0;i<K;i++){
			if(A.d[i]<minp[id].d[i]) res+=sqr(minp[id].d[i]-A.d[i]);
			if(A.d[i]>maxp[id].d[i]) res+=sqr(maxp[id].d[i]-A.d[i]);
		}
		return res;
	}
	void ask(int id){
		double d0=0;
		for(int i=0;i<K;i++) d0+=sqr(p[id].d[i]-A.d[i]);
		if(d0>0&&d0<ans) ans=d0;
		double dl=(ls[id])?getdis(ls[id]):1e18;
		double dr=(rs[id])?getdis(rs[id]):1e18;
		if(dl<dr) 
			{if(dl<ans) ask(ls[id]); if(dr<ans) ask(rs[id]);}
		else
			{if(dr<ans) ask(rs[id]); if(dl<ans) ask(ls[id]);}
	}
	double ask(Point _A){
		A=_A;
		ask(root);
		return ans;
	}
}kdt;

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=0;j<K;j++)
			scanf("%lf",&p[i].d[j]);
	memcpy(kdt.p,p,sizeof(p));
	kdt.build(root,1,n,0);
	kdt.ans=1e18;
	for(int i=1;i<=n;i++) kdt.ask(p[i]);
	printf("%.3lf\n",sqrt(kdt.ans));
	return 0;
}
posted @ 2020-11-16 16:40  BakaCirno  阅读(43)  评论(0编辑  收藏  举报