BZOJ 4520: [Cqoi2016]K远点对

4520: [Cqoi2016]K远点对

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 638  Solved: 340
[Submit][Status][Discuss]

Description

已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。

 

Input

输入文件第一行为用空格隔开的两个整数 N, K。接下来 N 行,每行两个整数 X,Y,表示一个点
的坐标。1 < =  N < =  100000, 1 < =  K < =  100, K < =  N*(N−1)/2 , 0 < =  X, Y < 2^31。
 

Output

输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数)。

 

Sample Input

10 5
0 0
0 1
1 0
1 1
2 0
2 1
1 2
0 2
3 0
3 1

Sample Output

9

HINT

 

Source

 
[Submit][Status][Discuss]

建立KD-Tree,用堆维护当前找到的前K远点对。

枚举一个点,在树中遍历,尝试更新堆顶(较近的点对)。

注意用KD-Tree“估价函数”来剪枝,还有因为点对有重复,所以应当取出第2K远的点对。

  1 #include <bits/stdc++.h>
  2 
  3 const int siz = 100005;
  4 
  5 int n, m;
  6 
  7 struct node
  8 {
  9     int son[2];
 10     int pos[2];
 11     int maxi[2];
 12     int mini[2];
 13 }tr[siz];
 14 
 15 int cmpk;
 16 
 17 inline bool cmp(const node &a, const node &b)
 18 {
 19     if (a.pos[cmpk] != b.pos[cmpk])
 20         return a.pos[cmpk] < b.pos[cmpk];
 21     else
 22         return a.pos[cmpk^1] < b.pos[cmpk^1];
 23 }
 24 
 25 int build(int l, int r, int k)
 26 {
 27     int mid = (l + r) >> 1; cmpk = k;
 28 
 29     std::nth_element(tr + l, tr + mid, tr + r + 1, cmp);
 30 
 31     if (l < mid)tr[mid].son[0] = build(l, mid - 1, k ^ 1);
 32     if (r > mid)tr[mid].son[1] = build(mid + 1, r, k ^ 1);
 33 
 34     tr[mid].maxi[0] = tr[mid].mini[0] = tr[mid].pos[0];
 35     tr[mid].maxi[1] = tr[mid].mini[1] = tr[mid].pos[1];
 36 
 37     for (int i = 0; i < 2; ++i)if (tr[mid].son[i])
 38         for (int j = 0; j < 2; ++j)
 39         {
 40             if (tr[mid].maxi[j] < tr[tr[mid].son[i]].maxi[j])
 41                 tr[mid].maxi[j] = tr[tr[mid].son[i]].maxi[j];
 42             if (tr[mid].mini[j] > tr[tr[mid].son[i]].mini[j])
 43                 tr[mid].mini[j] = tr[tr[mid].son[i]].mini[j];
 44         }
 45     
 46     return mid;
 47 }
 48 
 49 typedef long long lnt;
 50 
 51 const lnt inf = 2e18;
 52 
 53 std::priority_queue<
 54     lnt, std::vector<lnt>, std::greater<lnt>
 55 > heap;
 56 
 57 int qx, qy;
 58 
 59 inline lnt sqr(lnt x)
 60 {
 61     return x * x;
 62 }
 63 
 64 inline lnt calc(int t)
 65 {
 66     lnt dx = std::max(sqr(tr[t].mini[0] - qx), sqr(tr[t].maxi[0] - qx));
 67     lnt dy = std::max(sqr(tr[t].mini[1] - qy), sqr(tr[t].maxi[1] - qy));
 68 
 69     return dx + dy;
 70 }
 71 
 72 void query(int t)
 73 {
 74     lnt dis = sqr(tr[t].pos[0] - qx) + sqr(tr[t].pos[1] - qy);
 75 
 76     if (dis > heap.top())
 77     {
 78         heap.pop();
 79         heap.push(dis);
 80     }
 81 
 82     lnt dl = tr[t].son[0] ? calc(tr[t].son[0]) : -inf;
 83     lnt dr = tr[t].son[1] ? calc(tr[t].son[1]) : -inf;
 84 
 85     if (dl > dr)
 86     {
 87         if (dl > heap.top())query(tr[t].son[0]);
 88         if (dr > heap.top())query(tr[t].son[1]);
 89     }
 90     else
 91     {
 92         if (dr > heap.top())query(tr[t].son[1]);
 93         if (dl > heap.top())query(tr[t].son[0]);
 94     }
 95 }
 96 
 97 signed main(void)
 98 {
 99     scanf("%d%d", &n, &m);
100 
101     for (int i = 1; i <= n; ++i)
102         scanf("%d%d", &tr[i].pos[0], &tr[i].pos[1]);
103     
104     int root = build(1, n, 0);
105 
106     for (int i = 1; i <= 2*m; ++i)
107         heap.push(0LL);
108     
109     for (int i = 1; i <= n; ++i)
110     {
111         qx = tr[i].pos[0];
112         qy = tr[i].pos[1];
113         query(root);
114     }
115 
116     printf("%lld
", heap.top());
117 }

@Author: YouSiki

原文地址:https://www.cnblogs.com/yousiki/p/6284724.html