HDU 2996 In case of failure [KD树]

本文详细介绍了KD树的概念及其在计算几何中的应用,通过简洁高效的模版代码展示了如何使用KD树在点集中快速查找离指定点最近的点。重点讨论了KD树的构建和查找过程,提供了URBAL1369问题实例分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  KD树,来源计算几何,在《计算几何-算法与应用》一书中有详细的解释。

  这题是比较裸的KD树模型,要在点集中找到离一个点最近的一个点。其实KD树就是一棵多维平衡二叉树,将多维空间分成很多个部分,查找时能够较快的逼近查找点,从而快速的找到距离某点最近或者较近的点。

  在网上找到了这份模版,简洁高效。

  MARK一下URAL1369,也是一道KD树,目前TLE中。。。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #define MAXN 100005
 5 #define INF (1LL<<62)
 6 using namespace std;
 7 typedef long long LL;
 8 struct point{
 9     int x,y;
10 }p[MAXN],p2[MAXN];
11 bool dv[MAXN];
12 bool cmpx(const point& p1,const point& p2){
13     return p1.x<p2.x;
14 }
15 bool cmpy(const point& p1,const point& p2){
16     return p1.y<p2.y;
17 }
18 LL getdis(point p1,point p2){
19     return (LL)(p1.x-p2.x)*(p1.x-p2.x)+(LL)(p1.y-p2.y)*(p1.y-p2.y);
20 }
21 void buildKD(int l,int r,point p[]){
22     if(l==r)return;
23     int mid=(l+r)>>1;
24     //按照坐标范围选择建树轴
25     int minx=min_element(p+l,p+r,cmpx)->x;
26     int miny=min_element(p+l,p+r,cmpy)->y;
27     int maxx=max_element(p+l,p+r,cmpx)->x;
28     int maxy=max_element(p+l,p+r,cmpy)->y;
29     dv[mid]=(maxx-minx>=maxy-miny);
30     //dv[mid]=(step&1);也可以按照层数交替建树,貌似效率略慢
31     nth_element(p+l,p+mid,p+r,dv[mid]?cmpx:cmpy);
32     buildKD(l,mid,p);
33     buildKD(mid+1,r,p);
34 }
35 LL res=0;
36 void find(int l,int r,point a,point p[]){
37     if(l==r)return;
38     int mid=(l+r)>>1;
39     LL dist=getdis(a,p[mid]);
40     if(dist>0)res=min(res,dist);
41     LL d=dv[mid]?(a.x-p[mid].x):(a.y-p[mid].y);
42     int l1=l,l2=mid+1,r1=mid,r2=r;
43     if(d>0)swap(l1,l2),swap(r1,r2);
44     find(l1,r1,a,p);
45     if(d*d<res)find(l2,r2,a,p);
46 }
47 int n,cas;
48 int main(){
49     freopen("test.in","r",stdin);
50     scanf("%d",&cas);
51     while(cas--){
52         scanf("%d",&n);
53         for(int i=0;i<n;i++)
54             scanf("%d%d",&p[i].x,&p[i].y),p2[i]=p[i];
55         buildKD(0,n,p);
56         for(int i=0;i<n;i++){
57             res=INF;
58             find(0,n,p2[i],p);
59             printf("%I64d\n",res);
60         }
61 
62 
63     }
64     return 0;
65 }

 

  

转载于:https://www.cnblogs.com/swm8023/archive/2012/09/04/2670258.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值