#include <bits/stdc++.h> using namespace std; #define INT_INF 0x3fffffff #define EPS 1e-12 #define MOD 1000000007 #define PI 3.141592653579798 #define N 60000 struct data{ long long pos[10]; int id; } T[N] , op , point; int split[N],demension,now,n; bool use[N]; long long id,ans; double var[10]; bool cmp(data a,data b){ return a.pos[split[now]]<b.pos[split[now]]; } void build(int L,int R){ if(L>R) return; int mid=(L+R)>>1; for(int pos=0;pos<demension;pos++){ double ave=var[pos]=0.0; for(int i=L;i<=R;i++) ave+=T[i].pos[pos]; ave/=(R-L+1); for(int i=L;i<=R;i++) var[pos]+=(T[i].pos[pos]-ave)*(T[i].pos[pos]-ave); var[pos]/=(R-L+1); } split[now=mid]=0; for(int i=1;i<demension;i++) if(var[split[mid]]<var[i]) split[mid]=i; nth_element(T+L,T+mid,T+R+1,cmp); build(L,mid-1); build(mid+1,R); } void query(int L,int R){ if(L>R) return; int mid=(L+R)>>1; long long dis=0; for(int i=0;i<demension;i++) dis+=(op.pos[i]-T[mid].pos[i])*(op.pos[i]-T[mid].pos[i]); if(!use[T[mid].id] && dis<ans){ | K-D树 in 2 2 (2个二维点) out 0 0 the closest 1 1 1 points are: 1 (1个询问) 1 1 3 3 (询问点) 1 (求最近1个点) //pos[10]维度,id编号 //T[N] 树中的结点 //op当前要查询的结点(坐标) //point取得最近距离下的点 //分裂方式,维度,半点数,总点数 //已使用数组 //最近结点值及到分裂点距 //各维度方差存储数组
//区间为空则跳出 //取区间中点 //求出 每一维 上面的方差 //初始化VAR与平均值为0
//求此维度和 //求此维度平均值
//求此维度方差未平均 //求此维度方差
//半点数NOW用于后面排序,的确是从中间的点进宪分裂 //找到方差最大的那一维,用它来作为当前区间的 split_method //排第MID元素排到第MID的位置 //对左儿子建树 //对右儿子建树
//区间为空退出查询 //求中点编号
//求出目标点 op 到现在的根节点(分裂点)的距离 //根结点可用且ans可更新 |
ans=dis; point=T[mid]; id=T[mid].id; } long long radius= (op.pos[split[mid]]-T[mid].pos[split[mid]])* (op.pos[split[mid]]-T[mid].pos[split[mid]]); if(op.pos[split[mid]]<T[mid].pos[split[mid]]){ query(L,mid-1); if(radius<=ans) query(mid+1,R); }else{ query(mid+1,R); if(radius<=ans) query(L,mid-1); } } int main(){ while(scanf("%d%d",&n,&demension)!=EOF){ for(int i=1;i<=n;i++){ for(int j=0;j<demension;j++) scanf("%I64d",&T[i].pos[j]); T[i].id=i; } build(1,n); int m,q; scanf("%d",&q); while(q--){ memset(use,0,sizeof(use)); for(int i=0;i<demension;i++) scanf("%I64d",&op.pos[i]); scanf("%d",&m); printf("the closest %d points are:\n",m); while(m--){ ans=(((long long)INT_INF)*INT_INF); query(1,n); for(int i=0;i<demension;i++){ printf("%I64d",point.pos[i]); if(i==demension-1) printf("\n"); else printf(" "); } use[id]=1; } } } return 0; } | //更新最近距离 //更新取得最近距离下的点 //更新取得最近距离的点的 id
//计算 op 到分裂平面的距离的平方(当前要查询的点到当前点集的中间点之差的平方) //对子区间进行查询,小于则在左子树,大于则在右子树查,但是若到平面距小于等于到分裂点距则也要考虑另一边
//确定要输出多少个点及维度
//读入 n 个点 //记录本结点的编号,二叉树的结点就反映了父亲与儿子的关系 //建树 // q 个询问
//输入所要查询的点
//求到所给点最近的M个点 //(查一个删一个) //初始化无限大 //询问一次
//把询问所得到的点逐维度输出 //简单的换行与空格
//此结点已使用 |