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;
}