题意:k维空间n个点,t个询问,每次找m个最近点,保证答案唯一。
1 <= n <= 50000,1 <= k <= 5,1 <= t <= 10000,1 <= m <= 10,多组数据。
kdtree专属裸题。
有些网站说kdtree建树时每次找方差最小的一维建树什么的,我以亲身经历表示那根本不靠谱,这题坐标值范围才10000,算个方差都快爆double了,老老实实按12345维顺序建就好。。。
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
const size_t str=1<<16;
const char endl[]="\n";
struct Istream
{
char buf[str],*s,*t;
bool is_end;
Istream():buf(),s(),t(),is_end(0){}
inline char get()
{
if(s==t) t=buf+fread(s=buf,1,str-1,stdin);
if(s==t) return EOF;
return *s++;
}
inline Istream& operator >> (int &x)
{
register char c;
bool k=0;
x=0;
do
{
c=get();
if(c=='-') {c=get(),k=1;break;}
if(c==EOF) return is_end=1,*this;
}
while(c<'0'||c>'9');
while(c>='0'&&c<='9') x=x*10+c-'0',c=get();
if(k) x=-x;
return *this;
}
inline operator bool()
{
return !is_end;
}
}cin;
struct Ostream
{
unsigned char buf[str],*s,*t;
Ostream():buf(),s(buf),t(buf+str-1){}
~Ostream(){fwrite(buf,1,s-buf,stdout);}
inline void put(char c)
{
if(s==t) fwrite(s=buf,1,str-1,stdout);
*s++=c;
}
inline Ostream& operator << (int x)
{
static int a[15],t;
if(!x) return put('0'),*this;
if(x<0) put('-'),x=-x;
a[t=1]=x;
while(a[t]) a[t+1]=a[t]/10,a[t++]%=10;
while(--t) put(a[t]+'0');
return *this;
}
inline Ostream& operator << (const char *s)
{
while(*s) put(*s++);
return *this;
}
}cout;
int n,k,t,m;
int cmp;
struct pnt
{
int p[5];
pnt():p(){}
pnt(int* a){memcpy(p,a,k<<2);}
int& operator [] (size_t x){return p[x];}
const int &operator [] (size_t x) const {return p[x];}
inline bool operator < (const pnt &ano) const {return p[cmp]<ano[cmp];}
};
inline int dis(const pnt &a,const pnt &b)
{
int x,res=0;
for(int i=0;i<k;++i) x=abs(a[i]-b[i]),res+=x*x;
return res;
}
struct heap
{
struct ele
{
pnt *p;
int dis;
}h[11];
int n;
heap():h(),n(0){}
inline void push(pnt *__p,int __dis)
{
int i;
for(i=n-1;i>=0;--i)
if(__dis<h[i].dis) h[i+1]=h[i];
else break;
h[i+1]=(ele){__p,__dis};
if(n!=m) ++n;
}
inline bool able(int __dis)
{
return n!=m||__dis<h[m-1].dis;
}
friend inline Ostream& operator << (Ostream& out,const heap &a)
{
for(int i=0;i<m;++i)
{
pnt *x=a.h[i].p;
for(int j=0;j<k-1;++j)
out<<x->p[j]<<" ";
out<<x->p[k-1]<<endl;
}
return out;
}
};
inline void min(int &a,int b)
{
if(b<a) a=b;
}
inline void max(int &a,int b)
{
if(a<b) a=b;
}
struct node
{
pnt p,mn,mx;
node *l,*r;
node(const pnt &p):p(p),mn(p),mx(p),l(0),r(0){}
inline void up()
{
if(l) for(int i=0;i<k;++i)
min(mn[i],l->mn[i]),max(mx[i],l->mx[i]);
if(r) for(int i=0;i<k;++i)
min(mn[i],r->mn[i]),max(mx[i],r->mx[i]);
}
inline int min_dis(const pnt &a)
{
if(!this) return 0x7fffffff;
int res=0,now;
for(int i=0;i<k;++i)
{
if(a[i]<mn[i]) now=mn[i]-a[i];
else if(mx[i]<a[i]) now=a[i]-mx[i];
else now=0;
res+=now*now;
}
return res;
}
void get(const pnt &a,heap &h)
{
if(!this) return;
h.push(&p,dis(a,p));
int ld=l->min_dis(a),rd=r->min_dis(a);
if(ld<rd)
{
if(h.able(ld)) l->get(a,h);
if(h.able(rd)) r->get(a,h);
}
else
{
if(h.able(rd)) r->get(a,h);
if(h.able(ld)) l->get(a,h);
}
}
inline void* operator new(size_t);
};
char pool[50000*sizeof(node)];
int tot=-1;
inline void* node::operator new(size_t)
{
static node* s=(node*)pool;
return s+ ++tot;
}
node* build(pnt *l,pnt *r,int __cmp=0)
{
if(l==r) return 0;
int len=r-l;
pnt *mid=l+(len>>1);
cmp=__cmp;
std::nth_element(l,mid,r);
node *kre=new node(*mid);
kre->l=build(l,mid,__cmp==k-1?0:__cmp+1);
kre->r=build(mid+1,r,__cmp==k-1?0:__cmp+1);
kre->up();
return kre;
}
struct kdtree
{
node *rt;
kdtree(pnt *a,int len):rt(build(a,a+len)){}
~kdtree(){tot=-1;}
inline void print_m(pnt p)
{
heap h;
rt->get(p,h);
cout<<h;
}
};
pnt ar[50000],ask;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
while(cin>>n>>k)
{
for(int i=0;i<n;++i)
for(int j=0;j<k;++j)
cin>>ar[i][j];
kdtree tr(ar,n);
cin>>t;
while(t--)
{
for(int j=0;j<k;++j)
cin>>ask[j];
cin>>m;
cout<<"the closest "<<m<<" points are:\n";
tr.print_m(ask);
}
}
return 0;
}