[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
",ans);
        }
        for(int i=1;i<=n+5;++i)c[i][0]=c[i][1]=0;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zpengst/p/12790108.html