BZOJ 2626: JZPFAR

Description

求平面第\(k\)远的点,\(n\leqslant 10^5\)

Solution

KD-Tree.

用一个堆统计答案即可...

Code

/**************************************************************
    Problem: 2626
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:16080 ms
    Memory:4824 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
 
typedef long long LL;
const int N = 100050;
const int M = 2;
const int K = 25;
 
inline int in(int x=0,char s=getchar(),int v=1) { while(s>'9'||s<'0') v=s=='-'?-1:v,s=getchar();
    while(s>='0'&&s<='9') x=x*10+s-'0',s=getchar();return x*v; }
 
#define lc p[o].ch[0]
#define rc p[o].ch[1]
#define mid ((l+r)>>1)
#define sqr(x) ((x)*(x))
 
 
namespace KDTree {
    struct Node {
        int id,mi[M],mx[M],d[M],ch[2];
        Node() {
            id=ch[0]=ch[1]=0;
            for(int i=0;i<M;i++) mi[i]=mx[i]=d[i]=0;
        }
    }p[N];
     
    int D,cp,rt,k;Node qp;
    int cmp(const Node &a,const Node &b) { return a.d[D]<b.d[D]; }
    LL dis2(Node a,Node b) {
        LL d=0;
        for(int i=0;i<M;i++) d+=sqr((LL)a.d[i]-b.d[i]);
        return d;
    }
    double dis(Node a,Node b) { return sqrt(dis2(a,b)); }
    void Update(int o) {
        for(int i=0;i<M;i++) p[o].mx[i]=p[o].mi[i]=p[o].d[i];
        if(lc) for(int i=0;i<M;i++)
            p[o].mx[i]=max(p[o].mx[i],p[lc].mx[i]),p[o].mi[i]=min(p[o].mi[i],p[lc].mi[i]);
        if(rc) for(int i=0;i<M;i++)
            p[o].mx[i]=max(p[o].mx[i],p[rc].mx[i]),p[o].mi[i]=min(p[o].mi[i],p[rc].mi[i]);
    }
    void Build(int &o,int l,int r,int d) {
        D=d,o=mid,nth_element(p+l,p+o,p+r+1,cmp);
        if(l<mid) Build(lc,l,mid-1,(d+1)%M);
        if(r>mid) Build(rc,mid+1,r,(d+1)%M);
        Update(o);
    }
    LL S(int o) {
        LL res=0;
        for(int i=0;i<M;i++) res+=max(sqr((LL)p[o].mx[i]-qp.d[i]),sqr((LL)qp.d[i]-p[o].mi[i]));
        return res;
    }
    struct QNode { LL d2;int id; };
    bool operator < (const QNode &a,const QNode &b) { return a.d2==b.d2?a.id<b.id:a.d2>b.d2; }
    priority_queue<QNode> q;
    void Query(int o) {
        if(!o) return;
        LL d=dis2(p[o],qp),ll=lc?S(lc):-2,rr=rc?S(rc):-2;
        if((QNode) { d,p[o].id } < q.top()) q.pop(),q.push((QNode) { d,p[o].id });
        if(ll>rr) {
            if(ll>=q.top().d2) Query(lc);
            if(rr>=q.top().d2) Query(rc);
        } else {
            if(rr>=q.top().d2) Query(rc);
            if(ll>=q.top().d2) Query(lc);
        }
    }
     
    int Qur(int k,Node a) {
        for(;!q.empty();) q.pop();
        for(int i=0;i<k;i++) q.push((QNode) { -1,0 });
        qp=a;
        Query(rt);
        return q.top().id;
    }
};
 
using namespace KDTree;
 
int n,m;
 
int main() {
    cp=n=in();
    for(int i=1;i<=n;i++) {
        for(int j=0;j<M;j++) p[i].d[j]=in();
        p[i].id=i;
    }
    Build(rt=1,1,n,0);
    for(m=in();m--;) {
        Node a=Node();
        for(int j=0;j<M;j++) a.d[j]=in();
        int k=in();
        printf("%d\n",Qur(k,a));
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/beiyuoi/p/6741040.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值