题目描述
平面上有n个点。现在有m次询问,每次给定一个点(px, py)和一个整数k,输出n个点中离(px, py)的距离第k大的点的标号。如果有两个(或多个)点距离(px, py)相同,那么认为标号较小的点距离较大。
题解
- 利用KD-Tree算法,求二维平面内到一定点的第k远点
- 正常建树,由于题目要求输出第k远点的编号,我们需记录一下每个节点的id,用优先队列动态维护小根堆,保持k个最优点,最后输出堆顶元素的编号即可
代码
1 #include <queue>
2 #include <cstdio>
3 #include <cstring>
4 #include <iostream>
5 #include <algorithm>
6 #define sqr(x) (x)*(x)
7 #define N 100010
8 #define ll long long
9 using namespace std;
10 ll n,m,X,Y,tot,D,root;
11 struct node
12 {
13 ll dis,id;
14 bool operator < (const node &a)const { return dis>a.dis||(dis==a.dis&&id<a.id); }
15 };
16 struct Node
17 {
18 ll x[2],id;
19 bool operator < (const Node &a) const {return x[D]<a.x[D];}
20 }p[N];
21 struct kdtree { Node p; ll mx[2],mn[2],ls,rs,id; }t[N];
22 priority_queue<node>Q;
23 ll dis(kdtree t) { return sqr(t.p.x[0]-X)+sqr(t.p.x[1]-Y); }
24 ll mxdis(kdtree t) { return max(sqr((t.mn[0]-X)),sqr(t.mx[0]-X))+max(sqr(t.mn[1]-Y),sqr(t.mx[1]-Y)); }
25 void update(ll d)
26 {
27 if (!d) return;
28 ll l=t[d].ls,r=t[d].rs;
29 if (l) t[d].mn[0]=min(t[d].mn[0],t[l].mn[0]),t[d].mx[0]=max(t[d].mx[0],t[l].mx[0]),t[d].mn[1]=min(t[d].mn[1],t[l].mn[1]),t[d].mx[1]=max(t[d].mx[1],t[l].mx[1]);
30 if (r) t[d].mn[0]=min(t[d].mn[0],t[r].mn[0]),t[d].mx[0]=max(t[d].mx[0],t[r].mx[0]),t[d].mn[1]=min(t[d].mn[1],t[r].mn[1]),t[d].mx[1]=max(t[d].mx[1],t[r].mx[1]);
31 }
32 void build(ll &d,ll l,ll r,ll x)
33 {
34 if (l>r) return;
35 ll mid=l+r>>1;
36 D=x,d=++tot,nth_element(p+l,p+mid,p+r+1);
37 t[d].p=p[mid],t[d].id=t[d].p.id,t[d].mn[0]=t[d].mx[0]=t[d].p.x[0],t[d].mn[1]=t[d].mx[1]=t[d].p.x[1];
38 build(t[d].ls,l,mid-1,x^1),build(t[d].rs,mid+1,r,x^1),update(d);
39 }
40 void query(ll d)
41 {
42 if (!d) return;
43 ll p=dis(t[d]),l=t[d].ls,r=t[d].rs,L,R;
44 if (p>Q.top().dis||(p==Q.top().dis&&t[d].id<Q.top().id)) Q.pop(),Q.push((node){p,t[d].id});
45 if (l) L=mxdis(t[l]); if (r) R=mxdis(t[r]);
46 if (L>R)
47 {
48 if (L>=Q.top().dis) query(l);
49 if (R>=Q.top().dis) query(r);
50 }
51 else
52 {
53 if (R>=Q.top().dis) query(r);
54 if (L>=Q.top().dis) query(l);
55 }
56 }
57 int main()
58 {
59 scanf("%lld",&n);
60 for (ll i=1;i<=n;i++) scanf("%lld%lld",&p[i].x[0],&p[i].x[1]),p[i].id=i;
61 build(root,1,n,0),scanf("%lld",&m);
62 for (ll i=1,k;i<=m;i++)
63 {
64 scanf("%lld%lld%lld",&X,&Y,&k);
65 while (Q.size()) Q.pop();
66 for (ll j=1;j<=k;j++) Q.push((node){-1,0});
67 query(root),printf("%lld\n",Q.top().id);
68 }
69 }