BZOJ3053: The Closest M Points kdtree

题意: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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值