BZOJ3053 - The Closest M Points

原题链接

Description

给出K(K5)维空间中的n(n5×104)个点,然后t(t104)次询问距离某个坐标m(m10)近的点,将这m个点由近到远输出。坐标的绝对值不超过104

Solution

跟普通的k-d树差不多,就是要开一个容量为m的大根堆,初始堆里有minf,比较时如果比堆顶小就插入,如果到区间的距离都比堆顶要大就不需要做了。

Code

这个代码目前RE!又是对拍全过然后GG…

//The Closest M Points
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0,f=1; char ch=gc();
    while((ch<'0'||'9'<ch)&&ch!=EOF) {if(ch=='-') f=-1; ch=gc();}
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int const N=5e4+10;
int const INF=0x7FFFFFFF;
int n,K;
#define ch1 ch[p][0]
#define ch2 ch[p][1]
int rt,ch[N][2];
struct point{int c[5];} pt[N];
struct zone{int c1[5],c2[5];} zn[N];
int D; bool cmpPt(point x,point y) {return x.c[D]<y.c[D];}
void update(int p)
{
    for(int k=0;k<K;k++)
    {
        zn[p].c1[k]=min(pt[p].c[k],min(zn[ch1].c1[k],zn[ch2].c1[k]));
        zn[p].c2[k]=max(pt[p].c[k],max(zn[ch1].c2[k],zn[ch2].c2[k]));
    }
}
void build(int &p,int L,int R,int k0)
{
    p=L+R>>1; D=k0;
    nth_element(pt+L,pt+p,pt+R+1,cmpPt);
    if(L<p) build(ch[p][0],L,p-1,(k0+1)%K);
    if(p<R) build(ch[p][1],p+1,R,(k0+1)%K);
    update(p);
}
point A;
int dst(point B)
{
    int res=0; if(B.c[0]==INF) return INF;
    for(int k=0;k<K;k++) res+=(A.c[k]-B.c[k])*(A.c[k]-B.c[k]);
    return res;
}
int dst(zone z)
{
    int res=0;
    for(int k=0;k<K;k++)
        if(A.c[k]<z.c1[k]) res+=(z.c1[k]-A.c[k])*(z.c1[k]-A.c[k]);
        else if(z.c2[k]<A.c[k]) res+=(A.c[k]-z.c2[k])*(A.c[k]-z.c2[k]);
    return res;
}
#define pInt pair<int,int>
priority_queue< pInt,vector<pInt>,less<pInt> > q;
void query(int p)
{
    if(dst(pt[p])<dst(pt[q.top().second])) q.pop(),q.push(make_pair(dst(pt[p]),p));
    int p0=q.top().second;
    if(ch1&&dst(zn[ch1])<dst(pt[p0])) query(ch1);
    if(ch2&&dst(zn[ch2])<dst(pt[p0])) query(ch2);
}
int ans[20];
int main()
{
    while(true)
    {

    n=read(),K=read(); if(n==0) break;
    for(int k=0;k<K;k++) pt[0].c[k]=INF,zn[0].c1[k]=INF,zn[0].c2[k]=-INF;
    for(int i=1;i<=n;i++)
        for(int k=0;k<K;k++) pt[i].c[k]=read();
    build(rt,1,n,0);
    int t=read();
    while(t--)
    {
        for(int k=0;k<K;k++) A.c[k]=read();
        int m=read(); for(int i=1;i<=m;i++) q.push(make_pair(INF,0));
        query(rt);
        printf("the closest %d points are:\n",m);
        for(int i=m;i>=1;i--) ans[i]=q.top().second,q.pop();
        for(int i=1;i<=m;i++)
        {
            for(int k=0;k<K;k++) printf("%d ",pt[ans[i]].c[k]);
            printf("\n");
        }
        while(!q.empty()) q.pop();
    }

    }
    return 0;
}

P.S.

我好菜啊…

posted @ 2018-01-15 13:39  VisJiao  阅读(103)  评论(0编辑  收藏  举报