HYSBZ4520-K远点对

[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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值