BZOJ 2626 JZPFAR(KD-tree)

时间:2021-10-01 14:00:21

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2626

题意:平面上有n个点。现在有m次询问,每次给定一个点(px, py)和一个整数k,输出n个点中离(px, py)的距离第k大的点的标号。如果有两个(或多个)点距离(px, py)相同,那么认为标号较小的点距离较大。

思路:对n个点做KDtree。

 #include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define ll long long
struct Point{
ll d[],max[],min[];
int l,r,id;
}a[];
int root,n,K,cmpd,id[],m;
ll X,Y,ans[];
bool cmp(Point p1,Point p2){
if (p1.d[cmpd]!=p2.d[cmpd]) return p1.d[cmpd]<p2.d[cmpd];
else return p1.d[!cmpd]<p2.d[!cmpd];
}
void updata(int x){
if (a[x].l){
int j=a[x].l;
for (int i=;i<;i++)
a[x].max[i]=std::max(a[x].max[i],a[j].max[i]),
a[x].min[i]=std::min(a[x].min[i],a[j].min[i]);
}
if (a[x].r){
int j=a[x].r;
for (int i=;i<;i++)
a[x].max[i]=std::max(a[x].max[i],a[j].max[i]),
a[x].min[i]=std::min(a[x].min[i],a[j].min[i]);
}
}
ll sqr(ll x){
return x*x;
}
ll dist(int p,ll x,ll y){
ll dis=,d1,d2;
d1=std::abs(x-a[p].max[]);
d2=std::abs(x-a[p].min[]);
if (d1>d2) dis+=d1*d1;
else dis+=d2*d2;
d1=std::abs(y-a[p].max[]);
d2=std::abs(y-a[p].min[]);
if (d1>d2) dis+=d1*d1;
else dis+=d2*d2;
return dis;
}
void query(int p){
if (!p) return;
ll dl,dr,d0;
int t=K;
d0=sqr(std::abs(a[p].d[]-X))+sqr(std::abs(a[p].d[]-Y));
while (t&&(d0>ans[t]||(d0==ans[t]&&a[p].id<id[t]))) t--;
if (t!=K){
t++;
for (int i=K;i>=t+;i--){
ans[i]=ans[i-];
id[i]=id[i-];
}
ans[t]=d0;id[t]=a[p].id;
}
if (a[p].l) dl=dist(a[p].l,X,Y);else dl=;
if (a[p].r) dr=dist(a[p].r,X,Y);else dr=;
if (dl>dr){
if (dl>=ans[K]) query(a[p].l);
if (dr>=ans[K]) query(a[p].r);
}else{
if (dr>=ans[K]) query(a[p].r);
if (dl>=ans[K]) query(a[p].l);
}
}
int build(int l,int r,int d){
int mid=(l+r)/;
cmpd=d;
std::nth_element(a+l,a+mid,a++r,cmp);
a[mid].max[]=a[mid].min[]=a[mid].d[];
a[mid].max[]=a[mid].min[]=a[mid].d[];
if (l!=mid) a[mid].l=build(l,mid-,!d);
if (r!=mid) a[mid].r=build(mid+,r,!d);
updata(mid);
return mid;
}
int main(){
scanf("%d",&n);
for (int i=;i<=n;i++){
scanf("%lld%lld",&a[i].d[],&a[i].d[]);
a[i].id=i;
}
root=build(,n,);
scanf("%d",&m);
while (m--){
scanf("%lld%lld%d",&X,&Y,&K);
for (int i=;i<=;i++) id[i]=,ans[i]=;
query(root);
printf("%d\n",id[K]);
}
}