bzoj4520【CQOI2016】K远点对

4520: [Cqoi2016]K远点对

Time Limit: 30 Sec  Memory Limit: 512 MB

Submit: 497  Solved: 241

[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

KD-Tree+优先队列优化搜索

本体要求无序的K远点对,实际就是有序的2K远点对。

用优先队列记录当前最大的2K个距离,然后在KD-Tree上搜索,用优先队列优化。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define sqr(x) (x)*(x)
#define ll long long
#define N 100005
#define inf 1000000000000000ll
using namespace std;
int n,k,Q,root,lc[N],rc[N];
ll mn[N][2],mx[N][2];
priority_queue<ll,vector<ll>,greater<ll> > q;
struct data
{
	ll d[2];
	friend bool operator <(data a,data b)
	{
		return a.d[Q]!=b.d[Q]?a.d[Q]<b.d[Q]:a.d[Q^1]<b.d[Q^1];
	}
}tmp,val[N];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline ll calc(data a,data b){return sqr(a.d[0]-b.d[0])+sqr(a.d[1]-b.d[1]);}
void pushup(int x)
{
	F(i,0,1)
	{
		mn[x][i]=mx[x][i]=val[x].d[i];
		mn[x][i]=min(mn[x][i],min(mn[lc[x]][i],mn[rc[x]][i]));
		mx[x][i]=max(mx[x][i],max(mx[lc[x]][i],mx[rc[x]][i]));
	}
}
int build(int l,int r,int k)
{
	if (l>r) return 0;
	int mid=(l+r)>>1;
	Q=k;
	nth_element(val+l,val+mid,val+r+1);
	lc[mid]=build(l,mid-1,k^1);
	rc[mid]=build(mid+1,r,k^1);
	pushup(mid);
	return mid;
}
ll get(int x)
{
	if (!x) return 0;
	ll ret=0;
	F(i,0,1) ret+=max(sqr(mx[x][i]-tmp.d[i]),sqr(mn[x][i]-tmp.d[i]));
	return ret;
}
void query(int x)
{
	if (!x) return;
	ll dl=get(lc[x]),dr=get(rc[x]),d=calc(tmp,val[x]);
	if (d>q.top()) q.pop(),q.push(d);
	if (dl>dr)
	{
		if (dl>q.top()) query(lc[x]);
		if (dr>q.top()) query(rc[x]);
	}
	else
	{
		if (dr>q.top()) query(rc[x]);
		if (dl>q.top()) query(lc[x]);
	}
}
int main()
{
	n=read();k=read();
	F(i,1,n) val[i].d[0]=read(),val[i].d[1]=read();
	F(i,0,1) mn[0][i]=inf,mx[0][i]=-inf;
	root=build(1,n,0);
	F(i,1,2*k) q.push(0);
	F(i,1,n) tmp=val[i],query(root);
	printf("%lld\n",q.top());
	return 0;
}
时间: 2024-10-27 13:16:15

bzoj4520【CQOI2016】K远点对的相关文章

bzoj4520 [Cqoi2016]K远点对

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 远点对的距离的平方(一定是个整数). 将所有点建成kd

【BZOJ4520】[Cqoi2016]K远点对 kd-tree+堆

[BZOJ4520][Cqoi2016]K远点对 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 远点对

【BZOJ-4520】K远点对 KD-Tree + 堆

4520: [Cqoi2016]K远点对 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 490  Solved: 237[Submit][Status][Discuss] Description 已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对. Input 输入文件第一行为用空格隔开的两个整数 N, K.接下来 N 行,每行两个整数 X,Y,表示一个点 的坐标.1 < =  N < =  100000, 1 < =  K <

【bzoj4520】 Cqoi2016—K远点对

http://www.lydsy.com/JudgeOnline/problem.php?id=4520 (题目链接) 题意 求平面内第K远点对的距离. Solution 左转题解:jump 细节 刚开始我还开了两个堆,想想其实是没必要的→_→ 距离什么的开LL 代码 // bzoj4520 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include&

【bzoj4520】K远点对

Portal --> bzoj4520 Description 给你平面内\(n\)个点的坐标,求欧氏距离下第\(k\)远的点对 Solution 因为kd其实..严格来说挺不熟的用的太少了qwq 然后不知道为啥第一反应凸包直径取\(k\)次qwq然而这样有一个问题就是..取完一次之后删点不知道要删直径中两个点中的哪一个,所以..不太靠谱 正解应该是kd-tree 其实这题挺暴力的,时间复杂度也很玄学(不会算qwq)貌似kd的题复杂度就没有不玄学的.. 因为不知道答案是哪两个点,初步的想法是我们

BZOJ 4520 [Cqoi2016]K远点对(KD树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4520 [题目大意] 求K远点对距离 [题解] 修改估价函数为欧式上界估价,对每个点进行dfs, 因为是无向点对,在小根堆中保留前2k个距离, 不断更新堆顶元素即可. [代码] #include <cstdio> #include <algorithm> #include <queue> using namespace std; typedef long lo

[CQOI2016]K远点对

题目 这个题好像不是那样板子了 我们考虑维护一个有\(k\)个元素的小根堆,用来存我们当前找到的前\(k\)远点对 如果是暴力的话我们就直接暴力枚举点对,计算距离往这个小根堆里插就好了,非常显然,如果距离甚至小于小根堆的堆顶,我们就没有什么插入的必要了 考虑用\(kdt\)优化这个暴力,我们枚举每一个点,让这个点在\(kdt\)上搜,一旦发现某一个子矩形和这个点形成的最大欧几里得距离多于当前堆顶,我们就不用再往下计算了 又发现这样计算一个点对会被计算两次,所以我们实际上维护一个\(2k\)的小根

[CQOI2016]K远点对(KD-Tree)

暴力的做法应该是这样的,维护大小为k的堆,每次插入两点间距离并弹出堆顶. 然后这个做法显然是可以KD-Tree优化的,建立KD-Tree,然后如果该平面内最远点小于堆顶,则直接退出.就当做是复习很久没做的KD-Tree了. 不过有一个细节要注意,求最远点对,(1,2)->(2,1)算一对,所以堆的大小应该是2*k #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+7; st

LuoguP4357 [CQOI2016]K远点对

kd-tree #include<bits/stdc++.h> #define lc (ch[x][0]) #define rc (ch[x][1]) #define ll long long using namespace std; const int maxn=1e6+4; int n,m,cnt; ll mn[maxn][2],mx[maxn][2],ch[maxn][2],sz[maxn]; int nthdir; priority_queue<ll,vector<ll&g