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.
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.
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;
}