[KD-tree] Luogu P2093 JZPFAR

旧巷老猫 提交于 2019-11-26 09:57:08

题目描述

平面上有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 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!