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}