[Cqoi2016]K遠點對
Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 904 Solved: 466
[ 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
解題思路:kd-tree,建出kd-tree後,暴力枚舉每個點即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cctype>
#include <map>
#include <cmath>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
#define LL long long
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2000000 + 5;
const int demension = 2;//二維
struct node
{
int pos[demension];
int ma[demension], mi[demension];
int l, r;
}a[N], x;
int cmpDem;//以第cmpDem維作比較
int root, n, m, Size;
priority_queue<LL, vector<LL>, greater<LL> >q;
bool cmp(const node &a, const node&b)
{
if (a.pos[cmpDem] != b.pos[cmpDem]) return a.pos[cmpDem] < b.pos[cmpDem];
else return a.pos[!cmpDem] < b.pos[!cmpDem];
}
void Merge(int k)
{
for (int i = 0; i < demension; i++)
{
if (a[k].l)
{
a[k].ma[i] = max(a[k].ma[i], a[a[k].l].ma[i]);
a[k].mi[i] = min(a[k].mi[i], a[a[k].l].mi[i]);
}
if (a[k].r)
{
a[k].ma[i] = max(a[k].ma[i], a[a[k].r].ma[i]);
a[k].mi[i] = min(a[k].mi[i], a[a[k].r].mi[i]);
}
}
}
LL getdis(int k)
{
LL dis = 0;
for (int i = 0; i < demension; i++)
dis += max(1LL * (a[k].mi[i] - x.pos[i]) * (a[k].mi[i] - x.pos[i]), 1LL * (x.pos[i] - a[k].ma[i]) * (x.pos[i] - a[k].ma[i]));
return dis;
}
int build(int l, int r, int k)
{
if (l > r) return 0;
int mid = (l + r) / 2;
//以第mid個元素為中心排序
cmpDem = k;
nth_element(a + l, a + mid, a + r + 1, cmp);
//左右子樹
a[mid].l = build(l, mid - 1, k ^ 1);
a[mid].r = build(mid + 1, r, k ^ 1);
Merge(mid);
return mid;
}
void query(int k)
{
LL dis = 0;
for (int i = 0; i < demension; i++) dis += 1LL * (x.pos[i] - a[k].pos[i])*(x.pos[i] - a[k].pos[i]);
if (Size < m) q.push(dis), Size++;
else
{
LL pre = q.top();
if (pre < dis) q.pop(), q.push(dis);
}
LL dl = a[k].l ? getdis(a[k].l) : -1, dr = a[k].r ? getdis(a[k].r) : -1;
if (max(dl, dr) <= q.top() && Size >= m) return;
if (dl > dr)
{
if (Size < m || dl > q.top()) query(a[k].l);
if (Size < m || dr > q.top()) query(a[k].r);
}
else
{
if (Size < m || dr > q.top()) query(a[k].r);
if (Size < m || dl > q.top()) query(a[k].l);
}
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &a[i].pos[0], &a[i].pos[1]);
a[i].l = a[i].r = 0;
a[i].ma[0] = a[i].mi[0] = a[i].pos[0];
a[i].ma[1] = a[i].mi[1] = a[i].pos[1];
}
root = build(1, n, 0);
m *= 2;
Size = 0;
for (int i = 1; i <= n; i++)
{
x = a[i];
query(root);
}
printf("%lld\n", q.top());
while (!q.empty()) q.pop();
}
return 0;
}