hdu 4347 The Closest M Points (kd-tree+优先队列,求M近邻)
题意:
给出若干个点,在给出一个定点,求距离该定点最近的m个点。
思路:
我们已经知道kd-tree可以得到最近邻,实际上M近邻,只需要维护一个size为M的优先队列就可以了。
需要注意,优先队列的元素一定要先定义小于关系orz
以及这次采用了轮盘转的策略划分维度,也就是按照深度,所有维度轮流作为split-method(实际用起来效果还是挺棒的orz
1/* ***********************************************
2Author :111qqz
3Created Time :2017年10月08日 星期日 23时18分42秒
4File Name :4347.cpp
5************************************************ */
6
7#include <cstdio>
8#include <cstring>
9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define PB push_back
20#define fst first
21#define sec second
22#define lson l,m,rt<<1
23#define rson m+1,r,rt<<1|1
24#define ms(a,x) memset(a,x,sizeof(a))
25typedef long long LL;
26#define pi pair < int ,int >
27#define MP make_pair
28
29using namespace std;
30const double eps = 1E-8;
31const int dx4[4]={1,0,0,-1};
32const int dy4[4]={0,-1,1,0};
33const int inf = 0x3f3f3f3f;
34const int N=5E4+7;
35const int M = 10;
36int n,m,k,t;
37int idx;
38struct Point
39{
40 LL coor[M];
41 int id;
42 void print()
43 {
44 for ( int i = 1 ; i <= k ; i++)
45 printf("%lld%c",coor[i],i==k?'\n':' ');
46 }
47 bool operator < (const Point &u)const
48 {
49 return coor[idx]<u.coor[idx];
50 }
51}po[N];
52typedef pair< LL,Point >PI;
53priority_queue< PI >pq; //用优先队列一定要定义小于关系啊orz...我怎么这么傻
54struct KdTree
55{
56 Point p[N<<2];
57 bool leaf[N<<2];
58 void build ( int l,int r, int rt = 1,int dep=0)
59 {
60 if (l>r) return;
61 leaf[rt] = false;
62 leaf[rt<<1] = leaf[rt<<1|1] = true;
63 idx = dep % k;
64 int mid = (l+r)>>1;
65 nth_element(po+l,po+mid,po+r+1);
66 p[rt] = po[mid];
67 build(l,mid-1, rt<<1,dep+1);
68 build(mid+1,r,rt<<1|1,dep+1);
69 }
70 void query(Point tar,int rt=1,int dep=0)
71 {
72 if (leaf[rt]) return;
73 PI cur(0,p[rt]);
74 for ( int i = 1 ; i <= k ; i++) cur.fst += (p[rt].coor[i]-tar.coor[i])*(p[rt].coor[i]-tar.coor[i]);
75 int idx = dep%k;
76 int x=rt<<1,y=rt<<1|1,flag=0;
77 LL d = tar.coor[idx]-p[rt].coor[idx];
78 if (d>0) swap(x,y);
79 if (!leaf[x]) query(tar,x,dep+1);
80 if (pq.size()<m) pq.push(cur),flag=1;
81 else
82 {
83 if (cur.fst < pq.top().fst) pq.pop(),pq.push(cur);
84 if (d*d<pq.top().fst) flag = 1;
85 }
86 //cout<<pq.top().second.coor[0]<<" "<<pq.top().second.coor[1]<<endl;
87 if (!leaf[y]&&flag) query(tar,y,dep+1);
88 }
89}kd;
90int main()
91{
92 #ifndef ONLINE_JUDGE
93 freopen("./in.txt","r",stdin);
94 #endif
95 while (~scanf("%d %d",&n,&k))
96 {
97 for ( int i = 1 ; i <= n ; i++)
98 {
99 for ( int j = 1 ; j <= k ; j++) scanf("%lld",&po[i].coor[j]);
100 }
101 scanf("%d",&t);
102 kd.build(1,n);
103 while (t--)
104 {
105 Point ask;
106 for ( int i = 1 ; i <= k ; i++) scanf("%lld",&ask.coor[i]);
107 scanf("%d",&m);
108 kd.query(ask);
109 printf("the closest %d points are:\n",m);
110 Point ret[20];
111 //cout<<"pq_siz:"<<pq.size()<<" pq.top()"<<pq.top().sec.coor[1]<<endl;
112 for ( int i = 1 ; !pq.empty() ; i++) ret[i] = pq.top().second,pq.pop();
113 for ( int i = m ; i >= 1 ; i--) ret[i].print();
114 }
115 }
116 #ifndef ONLINE_JUDGE
117 fclose(stdin);
118 #endif
119 return 0;
120}