BZOJ 4520: [Cqoi2016]K远点对
4520: [Cqoi2016]K远点对
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 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
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
建立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\n", heap.top()); 117 }
@Author: YouSiki