HDU 2966 In case of failure 基础KD树

In case of failure

Time Limit: 60000/30000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2106    Accepted Submission(s): 880


Problem Description
To help their clients deal with faulty Cash Machines, the board of The Planar Bank has decided to stick a label expressing sincere regret and sorrow of the bank about the failure on every ATM. The very same label would gently ask the customer to calmly head to the nearest Machine (that should hopefully
work fine).


In order to do so, a list of two-dimensional locations of all n ATMs has been prepared, and your task is to find for each of them the one closest with respect to the Euclidean distance.
 

Input
The input contains several test cases. The very first line contains the number of cases t (t <= 15) that follow. Each test cases begin with the number of Cash Machines n (2 <= n <= 10^5). Each of the next n lines contain the coordinates of one Cash Machine x,y (0 <= x,y <=10^9) separated by a space. No two
points in one test case will coincide.
 

Output
For each test case output n lines. i-th of them should contain the squared distance between the i-th ATM from the input and its nearest neighbour.
 

Sample Input
  
  
2 10 17 41 0 34 24 19 8 28 14 12 45 5 27 31 41 11 42 45 36 27 15 0 0 1 2 2 3 3 2 4 0 8 4 7 4 6 3 6 1 8 0 11 0 12 2 13 1 14 2 15 0
 

Sample Output
  
  
200 100 149 100 149 52 97 52 360 97 5 2 2 2 5 1 1 2 4 5 5 2 2 2 5
 

Source




解题思路:

参考链接:https://my.oschina.net/keyven/blog/221792 写的不错

其他的没什么,就是模板弄懂了,kd树挺好写

具体写法都在代码里了。


#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define pow2(x) (x)*(x)
using namespace std;
const int N=100005;
const LL INF=0x3fffffffffffffff;///LL的最大值

int n,idx;   ///n为点数
struct point {
    LL x[3];
    bool operator < (const point &u) const {///每次排序按照对应的idx维度排序
        return x[idx]<u.x[idx];
    }
} po[N],poo[N];

typedef pair<LL,point> tp; ///pair,排序先按照LL从小到大,再按照point的排
LL ans = 0;

struct kdTree {
    point pt[N<<2];///树上的所有节点、所有节点都是坐标
    int son[N<<2];///树上的所有节点、记录的是每个节点的极差(其实主要看是否还有儿子)

    void build(int l,int r,int rt,int dep) {///2个默认参数
        if(l>r) return;///边界
        son[rt]=r-l;///有儿子
        son[rt<<1]=-1;///初始化左儿子
        son[rt<<1|1]=-1;///初始化右儿子
        idx=dep%2;///一直在k个维度间循环划分下去0 1 2 .... k-1。 0 1 ....
        int mid=(l+r)>>1;///中间数的选取、选的是第mid大的数
        nth_element(po+l,po+mid,po+r+1);///部分排序,第mid大的数在mid的位置,比它小的前面,比他大的在后面
        pt[rt]=po[mid];///把第mid大的点存在树中
        build(l,mid-1,rt<<1,dep+1);///递归建立左儿子
        build(mid+1,r,rt<<1|1,dep+1);///递归建立右儿子
    }
    void query(point p,int rt,int dep) {///查询点p的最近的点
        if(son[rt]==-1) return;///边界
        tp nd(0,pt[rt]);///pair的构造器,(距离、节点对应的点)

        nd.first+=pow2(nd.second.x[0]-p.x[0]);
        nd.first+=pow2(nd.second.x[1]-p.x[1]);

        int dim=dep%2;
        int x=rt<<1;///左儿子
        int y=rt<<1|1;///右儿子
        if(p.x[dim]>=pt[rt].x[dim]) {///如果p在dim维度上坐标大于等于父节点的值
            swap(x,y);///去右儿子
        }
        if(son[x]!=-1) {///如果有儿子
            query(p,x,dep+1);
        }
        if(ans>nd.first&&nd.first!=0){///需要忽略找到自己
            ans = nd.first ;
        }
        if(son[y]!=-1&&pow2(p.x[dim]-pt[rt].x[dim])<ans){///如果有另外的儿子,且点到其父节点的距离小于当前最小值ans
            query(p,y,dep+1);///在另外的分支中查询
        }
    }
} kd;

int main() {
    int t ;
    scanf("%d",&t) ;
    while(t--){
        int n ;
        scanf("%d",&n) ;
        for(int i=0;i<n;i++){
            scanf("%d %d",&po[i].x[0],&po[i].x[1]) ;
            poo[i] = po[i] ;
        }
        kd.build(0,n-1,1,0) ;///建树
        for(int i=0;i<n;i++){
            ans=INF;
            kd.query(poo[i],1,0) ;
            printf("%I64d\n",ans) ;
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值