HDU The Closest M Points【KD树求k近点】

题目描述:

RT。

题目分析:

点(x[0],x[1]…x[D])到矩形的最近距离的估价函数为:

int ret=0,tmp;
for(int j=0;j<D;j++) tmp=max(x[j]-t[i].mx[j],0)+max(t[i].mn[j]-x[j],0),ret+=tmp*tmp;

Code:

#include<bits/stdc++.h>
#define maxn 50005
using namespace std;
const int inf = 2147483646;
int n,m,k,D,id[maxn],rt,x[5];
struct node{
	int d[5],mn[5],mx[5],ch[2];
	void upd(node *t){
		for(int i=0;i<D;i++) mn[i]=mx[i]=d[i];
		for(int i=0;i<2;i++) if(ch[i]) for(int j=0;j<D;j++) mn[j]=min(mn[j],t[ch[i]].mn[j]),mx[j]=max(mx[j],t[ch[i]].mx[j]);	
	}
}t[maxn];
struct Pt{
	int x,y;
	bool operator < (const Pt &p)const{return x<p.x;}	
};
priority_queue<Pt>S;
template<int D>bool cmp(int i,int j){return t[i].d[D]<t[j].d[D];}
bool (*fun[5])(int i,int j)={cmp<0>,cmp<1>,cmp<2>,cmp<3>,cmp<4>};
void build(int &i,int l,int r,int nd){
	if(l>r) {i=0;return;}
	int o=(l+r)>>1;nth_element(id+l,id+o,id+r+1,fun[nd]),i=id[o];
	build(t[i].ch[0],l,o-1,(nd+1)%D),build(t[i].ch[1],o+1,r,(nd+1)%D);
	t[i].upd(t);
}
#define sqr(x) ((x)*(x))
inline int G(int i){
	if(!i) return inf;
	int ret=0,tmp;
	for(int j=0;j<D;j++) tmp=max(x[j]-t[i].mx[j],0)+max(t[i].mn[j]-x[j],0),ret+=tmp*tmp;
	return ret;
}
inline void ins(int i){
	Pt now=(Pt){0,i};
	for(int j=0;j<D;j++) now.x+=sqr(x[j]-t[i].d[j]);
	if(S.size()<k) S.push(now);
	else if(now<S.top()) S.pop(),S.push(now);
}
void query(int i){
	ins(i);
	int tmp[2]={G(t[i].ch[0]),G(t[i].ch[1])};int p=tmp[1]<tmp[0];
	if(t[i].ch[p]&&(S.size()<k||tmp[p]<S.top().x)) query(t[i].ch[p]);
	p^=1;
	if(t[i].ch[p]&&(S.size()<k||tmp[p]<S.top().x)) query(t[i].ch[p]);
}
inline void output(){
	if(!S.empty()){
		int i=S.top().y; S.pop(),output();
		for(int j=0;j<D;j++) printf("%d%c",t[i].d[j]," \n"[j==D-1]);
	}
}
int main()
{
	while(~scanf("%d%d",&n,&D)){
		for(int i=1;i<=n;i++) {id[i]=i;for(int j=0;j<D;j++) scanf("%d",&t[i].d[j]);}
		build(rt,1,n,0);
		scanf("%d",&m);
		while(m--){
			for(int i=0;i<D;i++) scanf("%d",&x[i]); scanf("%d",&k);
			printf("the closest %d points are:\n",k);
			query(rt),output();
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值