The Closest M Points BZOJ 3053

The Closest M Points

【问题描述】

软工学院的课程很讨厌!ZLC同志遇到了一个头疼的问题:在K维空间里面有许多的点,对于某些给定的点,ZLC需要找到和它最近的m个点。

(这里的距离指的是欧几里得距离:D(p, q) = D(q, p) =  sqrt((q1 - p1) ^ 2 + (q2 - p2) ^ 2 + (q3 - p3) ^ 2 + ... + (qn - pn) ^ 2)

ZLC要去打Dota,所以就麻烦你帮忙解决一下了……

【输入格式】

第一行,两个非负整数:点数n(1 <= n <= 50000),和维度数k(1 <= k <= 5)。

接下来的n行,每行k个整数,代表一个点的坐标。

接下来一个正整数:给定的询问数量t(1 <= t <= 10000)

下面2*t行:

  第一行,k个整数:给定点的坐标

  第二行:查询最近的m个点(1 <= m <= 10)

所有坐标的绝对值不超过10000。

有多组数据!

【输出格式】

对于每个询问,输出m+1行:

第一行:"the closest m points are:" m为查询中的m

接下来m行每行代表一个点,按照从近到远排序。

保证方案唯一,下面这种情况不会出现:

2 2

1 1

3 3

1

2 2

1

【样例输入】

3 2

1 1

1 3

3 4

2

2 3

2

2 3

1

【样例输出】

5

0

4

 


题解:

题意就是求与给定点第一近到第m近的点

用KD树查询

期望答案的计算:与给定点最近且不与给定点在同一块的期望点必定在边界上

开始时先将m个inf加入

那么当查询到的点与给定点的距离小于堆顶与给定点的距离时,就去掉堆顶并加入这个点

最后倒序输出

注意初始化(虽然没写什么初始化,但是要考虑一下的)

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<queue>
  8 using namespace std;
  9 inline void Scan(int &x)
 10 {
 11     int o = 1;
 12     char c;
 13     while((c = getchar()) < '0' || c > '9')
 14         if(c == '-') o = -1;
 15     x = c - '0';
 16     while((c = getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
 17     x *= o;
 18 }
 19 const int me = 50233;
 20 const int inf = 2147483647;
 21 struct dot
 22 {
 23     int lc, rc;
 24     int dis;
 25     int v[6], mi[6], ma[6];
 26 };
 27 dot point;
 28 dot c[me];
 29 dot tr[me];
 30 dot ans[me];
 31 struct name
 32 {
 33     int x;
 34     int dis;
 35 };
 36 inline bool operator < (const name &a, const name &b)
 37 {
 38     return a.dis < b.dis;
 39 }
 40 priority_queue <name> sta;
 41 int e, n, k, m;
 42 inline bool cmp(const dot &a, const dot &b)
 43 {
 44     return a.v[e] < b.v[e];
 45 }
 46 inline int Min(const int &x, const int &y)
 47 {
 48     return (x < y) ? x : y;
 49 }
 50 inline int Max(const int &x, const int &y)
 51 {
 52     return (x > y) ? x : y;
 53 }
 54 inline int Sqr(const int &x)
 55 {
 56     return x * x;
 57 }
 58 inline void Update(const int &x)
 59 {
 60     int l = tr[x].lc, r = tr[x].rc;
 61     for(int i = 0; i < k; ++i)
 62     {
 63         tr[x].mi[i] = tr[x].ma[i] = tr[x].v[i];
 64         if(l) tr[x].mi[i] = Min(tr[x].mi[i], tr[l].mi[i]), tr[x].ma[i] = Max(tr[x].ma[i], tr[l].ma[i]);
 65         if(r) tr[x].mi[i] = Min(tr[x].mi[i], tr[r].mi[i]), tr[x].ma[i] = Max(tr[x].ma[i], tr[r].ma[i]);
 66     }
 67 }
 68 int Build(const int &l, const int &r, int d)
 69 {
 70     if(d >= k) d -= k;
 71     e = d;
 72     int mi = l + r >> 1;
 73     nth_element(c + l, c + mi, c + r + 1, cmp);
 74     tr[mi] = c[mi];
 75     if(l < mi) tr[mi].lc = Build(l, mi - 1, d + 1);
 76     if(r > mi) tr[mi].rc = Build(mi + 1, r, d + 1);
 77     Update(mi);
 78     return mi;
 79 }
 80 inline int Dis(const int &x)
 81 {
 82     int sum = 0;
 83     for(int i = 0; i < k; ++i)
 84         sum += Sqr(tr[x].v[i] - point.v[i]);
 85     return sum;
 86 }
 87 inline int Get(const int &x)
 88 {
 89     int sum = 0;
 90     for(int i = 0; i < k; ++i)
 91     {
 92         if(point.v[i] < tr[x].mi[i]) sum += Sqr(tr[x].mi[i] - point.v[i]);
 93         if(point.v[i] > tr[x].ma[i]) sum += Sqr(point.v[i] - tr[x].ma[i]);
 94     }
 95     return sum;
 96 }
 97 void Ask(const int &x)
 98 {
 99     int dis = Dis(x);
100     if(dis < sta.top().dis)
101     {
102         sta.pop();
103         sta.push((name) {x, dis});
104     }
105     int le = inf, ri = inf;
106     if(tr[x].lc) le = Get(tr[x].lc);
107     if(tr[x].rc) ri = Get(tr[x].rc);
108     if(le < ri)
109     {
110         if(le < sta.top().dis) Ask(tr[x].lc);
111         if(ri < sta.top().dis) Ask(tr[x].rc);
112     }
113     else
114     {
115         if(ri < sta.top().dis) Ask(tr[x].rc);
116         if(le < sta.top().dis) Ask(tr[x].lc);
117     }
118 }
119 int main()
120 {
121 //    freopen("d.in", "r", stdin), freopen("d.out", "w", stdout);
122     while(~scanf("%d", &n))
123     {
124         Scan(k);
125         for(int i = 1; i <= n; ++i)
126             for(int j = 0; j < k; ++j)
127                 Scan(c[i].v[j]);
128         int root = Build(1, n, 0);
129         int t;
130         Scan(t);
131         while(t--)
132         {
133             for(int i = 0; i < k; ++i) Scan(point.v[i]);
134             Scan(m);
135             for(int i = 1; i <= m; ++i) sta.push((name) {0, inf});
136             Ask(root);
137             for(int i = 1; i <= m; ++i)
138             {
139                 ans[i] = tr[sta.top().x];
140                 sta.pop();
141             }
142             printf("the closest %d points are:\n", m);
143             for(int i = m; i >= 1; --i)
144             {
145                 for(int j = 0; j < k - 1; ++j)
146                     printf("%d ", ans[i].v[j]);
147                 printf("%d\n", ans[i].v[k - 1]);
148             }
149         }
150     }
151 }
posted @ 2017-02-25 16:47  草根柴鸡  阅读(147)  评论(0编辑  收藏  举报