bzoj 4520: [Cqoi2016]K远点对 k-d tree

本文介绍了一种结合KD树和优先队列的数据结构优化方案,用于解决大规模数据集上的近邻搜索问题。通过构建KD树来减少搜索范围,并利用优先队列维护最近的邻居点,有效提升了搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       用优先队列维护一下最大的k个,然后和第k个比较看能否更新即可。枚举每个点直接在k-d tree里面查询,这样会造成重复就把k变成2k即可。

AC代码如下:

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
#define ll long long
#define sqr(x) (ll)(x)*(x)
using namespace std;

int n,m,dms,tx,ty,rt,h[100005];
void up(int &x,int y){ if (x<y) x=y; }
void dn(int &x,int y){ if (x>y) x=y; }
priority_queue<ll,vector<ll>,greater<ll> > q;
struct node{
	int d[2],x[2],y[2],ls,rs;
	void pfs(int u,int v){
		d[0]=x[0]=x[1]=u; d[1]=y[0]=y[1]=v;
	}
}p[100005];
bool cmp(int x,int y){ return p[x].d[dms]<p[y].d[dms]; }
struct kd_tree{
	void maintain(int k,int t){
		dn(p[k].x[0],p[t].x[0]); up(p[k].x[1],p[t].x[1]);
		dn(p[k].y[0],p[t].y[0]); up(p[k].y[1],p[t].y[1]);
	}
	void build(int &k,int l,int r,int now){
		int mid=(l+r)>>1; dms=now;
		nth_element(h+l,h+mid,h+r+1,cmp); k=h[mid];
		if (l<mid){ build(p[k].ls,l,mid-1,now^1); maintain(k,p[k].ls); }
		if (mid<r){ build(p[k].rs,mid+1,r,now^1); maintain(k,p[k].rs); }
	}
	ll calc(int k){
		return max(sqr(p[k].x[0]-tx),sqr(p[k].x[1]-tx))+max(sqr(p[k].y[0]-ty),sqr(p[k].y[1]-ty));
	}
	void qry(int k,int now){
		ll dl=calc(p[k].ls),dr=calc(p[k].rs),dk=sqr(p[k].d[0]-tx)+sqr(p[k].d[1]-ty);
		if (dk>q.top()){ q.pop(); q.push(dk); }
		if (dl>dr){
			if (p[k].ls && dl>q.top()) qry(p[k].ls,now^1);
			if (p[k].rs && dr>q.top()) qry(p[k].rs,now^1);
		} else{
			if (p[k].rs && dr>q.top()) qry(p[k].rs,now^1);
			if (p[k].ls && dl>q.top()) qry(p[k].ls,now^1);
		}
	}
}kd;
int main(){
	scanf("%d%d",&n,&m); int i,x,y;
	for (i=1; i<=n; i++){
		h[i]=i; scanf("%d%d",&x,&y);
		p[i].pfs(x,y);
	}
	kd.build(rt,1,n,0);
	for (i=1; i<=(m<<1); i++) q.push(0);
	for (i=1; i<=n; i++){
		tx=p[i].d[0]; ty=p[i].d[1];
		kd.qry(rt,0);
	}
	printf("%lld\n",q.top());
	return 0;
}


by lych

2016.4.14

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值