http://acm.hdu.edu.cn/showproblem.php?pid=4347
K-D树板题,这题是照着别人的代码抄的,感觉不是很符合我的风格,之后再改。
对于K-D树我的理解感觉还是不太对,之后得多看点博客,再做点题理解才好
首先建树是按照线段树的方式向下建的,然后每一层按照他的深度取不同维度的中位数放在当前点,然后继续向下递归建树。
然后我们再查询的时候,先判断询问的点在当前层应该放到左边还是右边,那么那个子树在该维上的距离就会尽可能小,但是我们不知道在其他维上是否会一样小,所以用一个flag来标记是否需要去另外一棵子树上找,还可以添加答案的,一定要去另一颗上找,否则要看如果当前子树的根节点的对应维度的距离如果是严格小于答案中最大的,那么也需要去另一棵子树上去找找。
所以这就是一个剪枝,看了网上博客说随机数据复杂度是O(logn)的,而对于构造数据会被卡到O(sqrt(n))的水平
#include<bits/stdc++.h>
using namespace std;
const int maxl=5e4+10;
int n,k,m,idx;
struct point
{
int x[5];
bool operator < (const point &b)const
{
return x[idx]<b.x[idx];
}
}a[maxl],ans[21];
typedef pair<double,point> pdp;
priority_queue<pdp> q;
struct tree
{
point p[maxl<<2];
int son[maxl<<2];
void build(int l,int r,int u,int dep)
{
if(l>r) return;
son[u]=r-l+1;
son[u<<1]=son[u<<1|1]=0;
idx=dep%k;
int mid=(l+r)>>1;
nth_element(a+l,a+mid,a+r+1);
p[u]=a[mid];
build(l,mid-1,u<<1,dep+1);
build(mid+1,r,u<<1|1,dep+1);
}
void query(point d,int m,int u,int dep)
{
pdp nd(0,p[u]);
for(int i=0;i<k;i++)
nd.first+=pow(p[u].x[i]-d.x[i],2);
int id=dep%k,flag=0;
int x=u<<1,y=u<<1|1;
if(d.x[id]>=p[u].x[id])
swap(x,y);
if(son[x])
query(d,m,x,dep+1);
if(q.size()<m)
q.push(nd),flag=1;
else
{
if(nd.first<q.top().first)
q.pop(),q.push(nd);
if(pow(d.x[id]-p[u].x[id],2)<q.top().first)
flag=1;
}
if(son[y] && flag)
query(d,m,y,dep+1);
}
}kd;
inline void prework()
{
for(int i=1;i<=n;i++)
for(int j=0;j<k;j++)
scanf("%d",&a[i].x[j]);
kd.build(1,n,1,0);
}
inline void mainwork()
{
int t;point d;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
for(int j=0;j<k;j++)
scanf("%d",&d.x[j]);
scanf("%d",&m);
while(!q.empty())
q.pop();
kd.query(d,m,1,0);
printf("the closest %d points are:\n",m);
for(int j=1;j<=m;j++)
ans[j]=q.top().second,q.pop();
for(int j=m;j>=1;j--)
for(int ii=0;ii<k;ii++)
printf("%d%c",ans[j].x[ii],ii==k-1?'\n':' ');
}
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
prework();
mainwork();
}
return 0;
}