题目:
题解:
也是一道裸题嘛,只有ask的部分要好好想,到这个部分至少要花费的距离就是出界的范围
这里可以使用大根堆,每次和堆顶比较考虑要不要加进去,比小根堆节省时间空间哦
最后倒着输出就好啦
然后我这个zz调了1h30min+的程序,竟是因为没有清零!!!!!
代码:
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const double INF=1e18;
struct hh{int d[5],l,r,mn[5],mx[5];}t[50005],y,ans[20];
struct dui{hh di;double jl;bool operator <(const dui&a) const {return jl<a.jl;}};
int k,cmpd,num,m,root;
priority_queue<dui>q;
int cmp(const hh &a,const hh &b)
{
if (a.d[cmpd]!=b.d[cmpd]) return a.d[cmpd]<b.d[cmpd];
return a.d[(cmpd+1)%k]<b.d[(cmpd+1)%k];
}
void updata(int now)
{
int lc=t[now].l,rc=t[now].r;
if (lc)
{
for (int i=0;i<k;i++)
{
t[now].mn[i]=min(t[now].mn[i],t[lc].mn[i]);
t[now].mx[i]=max(t[now].mx[i],t[lc].mx[i]);
}
}
if (rc)
{
for (int i=0;i<k;i++)
{
t[now].mn[i]=min(t[now].mn[i],t[rc].mn[i]);
t[now].mx[i]=max(t[now].mx[i],t[rc].mx[i]);
}
}
}
int build(int l,int r,int D)
{
cmpd=D;
int mid=(l+r)>>1;
nth_element(t+l+1,t+mid+1,t+r+1,cmp);
for (int i=0;i<k;i++)
t[mid].mn[i]=t[mid].mx[i]=t[mid].d[i];
if (l!=mid) t[mid].l=build(l,mid-1,(D+1)%k);
if (r!=mid) t[mid].r=build(mid+1,r,(D+1)%k);
updata(mid); return mid;
}
double dis(int now)
{
double d=0;
for (int i=0;i<k;i++)
{
if (y.d[i]<t[now].mn[i]) d+=(double)((y.d[i]-t[now].mn[i])*(y.d[i]-t[now].mn[i]));
if (y.d[i]>t[now].mx[i]) d+=(double)((y.d[i]-t[now].mx[i])*(y.d[i]-t[now].mx[i]));
}
return d;
}
void ask(int now)
{
double d0=0,dl,dr;
for (int i=0;i<k;i++)
d0+=(double)((y.d[i]-t[now].d[i])*(y.d[i]-t[now].d[i]));
if (num<m) num++,q.push((dui){t[now],d0});
else if (q.top().jl>d0) q.pop(),q.push((dui){t[now],d0});
if (t[now].l) dl=dis(t[now].l);else dl=INF;
if (t[now].r) dr=dis(t[now].r);else dr=INF;
if (dl<dr)
{
if (dl!=INF && (dl<q.top().jl || num<m)) ask(t[now].l);
if (dr!=INF && (dr<q.top().jl || num<m)) ask(t[now].r);
}
else
{
if (dr!=INF && (dr<q.top().jl || num<m)) ask(t[now].r);
if (dl!=INF && (dl<q.top().jl || num<m)) ask(t[now].l);
}
}
int main()
{
int n,i,j,T;
while (~scanf("%d%d",&n,&k))
{
memset(t,0,sizeof(t));
for (i=1;i<=n;i++)
for (j=0;j<k;j++)
scanf("%d",&t[i].d[j]);
root=build(1,n,0);
scanf("%d",&T);
while (T--)
{
for (i=0;i<k;i++) scanf("%d",&y.d[i]);
scanf("%d",&m);num=0;
ask(root);
printf("the closest %d points are:\n",m);
for (i=1;i<=m;i++) {ans[i]=q.top().di; q.pop();}
for (i=m;i>=1;i--)
{
for (j=0;j<k-1;j++) printf("%d ",ans[i].d[j]);
printf("%d\n",ans[i].d[k-1]);
}
}
}
}