[HDU2966]In case of failure——KD树
In case of failure
题意:二维平面,求每个点与它最近的点的距离。
KD树模板。依次选择每个维度进行划分建树。也可以选择方差最大的一维进行划分。随机划分也过了。奇怪的是用定义求方差一直TLE,用D(X) = E(X^2) - E(X)^2 就没有问题,可能是爆精度?最简洁的实现是每个节点直接用(l+r)/2作为节点编号。这里没有用这种方法。代码参考了n+e的ppt。
#include<bits/stdc++.h> typedef long long ll; using namespace std; #define cmax(a,b) (a<b?a=b:a) #define cmin(a,b) (a>b?a=b:a) inline ll sqr(ll x){return x*x;} const ll INF=3e18; const int N=1e5+10; int D; struct Point{int d[2];}p[N],q[N]; inline bool cmp(Point a,Point b){return a.d[D]<b.d[D];} //d:每个维度的值,c:子节点,x:x的范围,y:y的范围, int d[N][2],c[N][2],x[N][2],y[N][2],tot; void pushup(int o,int son){ cmin(x[o][0],x[son][0]);cmax(x[o][1],x[son][1]); cmin(y[o][0],y[son][0]);cmax(y[o][1],y[son][1]); } void build(int &o,int l,int r,int di){//闭区间 o=++tot;D=di; int mid=(l+r)>>1; nth_element(p+l,p+mid,p+r+1,cmp); d[o][0]=x[o][0]=x[o][1]=p[mid].d[0]; d[o][1]=y[o][0]=y[o][1]=p[mid].d[1]; if(l<mid)build(c[o][0],l,mid-1,di^1),pushup(o,c[o][0]); if(mid<r)build(c[o][1],mid+1,r,di^1),pushup(o,c[o][1]); } ll ans; inline ll eva(Point a,int o){//估计最小欧几里德距离 return sqr(max(max(x[o][0]-a.d[0],a.d[0]-x[o][1]),0))+ sqr(max(max(y[o][0]-a.d[1],a.d[1]-y[o][1]),0)); } void query(int o,Point a){ ll tmp=sqr(a.d[0]-d[o][0])+sqr(a.d[1]-d[o][1]),Min[2]; if(tmp)cmin(ans,tmp); if(c[o][0])cmin(Min[0],eva(a,c[o][0]));else Min[0]=INF; if(c[o][1])cmin(Min[1],eva(a,c[o][1]));else Min[1]=INF; tmp=Min[0]>Min[1]; if(Min[tmp]<ans)query(c[o][tmp],a);tmp^=1; if(Min[tmp]<ans)query(c[o][tmp],a); } int main(){ int t,n,o; scanf("%d",&t); while(t--){ tot=0; scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d%d",&p[i].d[0],&p[i].d[1]),q[i]=p[i]; build(o,1,n,0); for(int i=1;i<=n;++i){ ans=INF;query(o,q[i]); printf("%lld\n",ans); } for(int i=1;i<=n+5;++i)c[i][0]=c[i][1]=0; } return 0; }