【HDU】2966 In case of failure【KD树】

传送门:【HDU】2966 In case of failure【KD树】

题意:给平面图上 N(1N105) 个点,对每个点,找到其他 欧几里德距离 离他最近的点,输出他们之间的距离。保证没有重点。

这是本弱学习 KD 树做的第一题。本题做法网上很多,我就不详细说了。

KD 树在算法竞赛中主要用来做各种各样的平面区域查询,包含则累加直接返回,相交则继续递归,相离的没有任何贡献也直接返回。可以处理圆,三角形,矩形等判断起来相对容易的平面区域内的符合加法性质的操作。

KD 树的建树:交替选择当前递归区间内所有点的横、纵坐标的中位数然后以此为新的划分点继续递归。因为每次都是划分成一半,而求中位数可以用 nth_element() 做到 O(N) ,因此复杂度为 T(N)=2T(N2)+O(N)=O(NlogN)

my   code:

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

const int MAXN = 100005 ;

struct Node {
    int p[2] ;
    int f , l , r ;
    int Min[2] , Max[2] ;
    int operator [] ( const int& idx ) const {
        return p[idx] ;
    }
    void input ( int idx ) {
        scanf ( "%d%d" , &p[0] , &p[1] ) ;
        f = idx ;
    }
    void up ( Node& a ) {
        Min[0] = min ( Min[0] , a.Min[0] ) ;
        Max[0] = max ( Max[0] , a.Max[0] ) ;
        Min[1] = min ( Min[1] , a.Min[1] ) ;
        Max[1] = max ( Max[1] , a.Max[1] ) ;
    }
} ;

Node T[MAXN] ;
int idx[MAXN] ;
int cmpw ;
int root ;
int n ;
LL ans ;

bool cmp ( const Node& a , const Node& b ) {
    return a[cmpw] < b[cmpw] ;
}

void up ( int o ) {
    if ( T[o].l ) T[o].up ( T[T[o].l] ) ;
    if ( T[o].r ) T[o].up ( T[T[o].r] ) ;
}

int build ( int l , int r , int w , int f ) {
    int mid = l + r >> 1 ;
    cmpw = w ;
    nth_element ( T + l , T + mid , T + r + 1 , cmp ) ;
    idx[T[mid].f] = mid ;
    //T[mid].f = f ;
    //T[mid].Min[0] = T[mid].Max[0] = T[f].p[0] ;
    //T[mid].Min[1] = T[mid].Max[1] = T[f].p[1] ;
    T[mid].l = l != mid ? build ( l , mid - 1 , !w , mid ) : 0 ;
    T[mid].r = r != mid ? build ( mid + 1 , r , !w , mid ) : 0 ;
    //up ( mid ) ;
    return mid ;
}

LL dist ( LL x , LL y = 0 ) {
    return x * x + y * y ;
}

LL query ( int o , int w , LL x , LL y ) {
    LL tmp = dist ( x - T[o][0] , y - T[o][1] ) ;
    if ( tmp ) ans = min ( ans , tmp ) ;
    if ( T[o].l && T[o].r ) {
        bool d = !w ? ( x <= T[o][0] ) : ( y <= T[o][1] ) ;
        LL dis = !w ? dist ( x - T[o][0] ) : dist ( y - T[o][1] ) ;
        query ( d ? T[o].l : T[o].r , !w , x , y ) ;
        if ( dis < ans ) query ( d ? T[o].r : T[o].l , !w , x , y ) ;
    }
    else if ( T[o].l ) query ( T[o].l , !w , x , y ) ;
    else if ( T[o].r ) query ( T[o].r , !w , x , y ) ;
}

void solve () {
    scanf ( "%d" , &n ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        T[i].input ( i ) ;
    }
    root = build ( 1 , n , 0 , 0 ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        ans = 9e18 ;
        query ( root , 0 , T[idx[i]][0] , T[idx[i]][1] ) ;
        printf ( "%lld\n" , ans ) ;
    }
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    for ( int i = 1 ; i <= T ; ++ i ) {
        solve () ;
    }
    return 0 ;
}

你可能感兴趣的:(【HDU】2966 In case of failure【KD树】)