K-D tree 解决K远点对问题

• 通过 K-D tree 和一个优先队列,可以查询距离一个钦定点第 K 远的点。

• 具体操作看起来似乎比较暴力。

  1. 首先将 K 个 “ 空 ” 的值存入队列。

  2. 暴力 dfs K-D tree 更新队列。

• 所有点对中的第 K 远点对显然只需要将队列全局化。


 

P2093 [国家集训队]JZPFAR  多组询问,K 较小。

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define ls    son[u][0]
  4 #define rs    son[u][1]
  5 #define inf 1e9
  6 using namespace std;
  7 int n,m,root,opt;
  8 int pos[100050];
  9 ll val[100050][2],x[2];
 10 ll L[100050][2],R[100050][2];
 11 int son[100050][2];
 12 struct node
 13 {
 14     int pos;
 15     ll    dis;
 16     bool operator<(const node &p)const
 17     {
 18         return dis==p.dis? pos<p.pos:dis>p.dis;
 19     }
 20 }num[100050];
 21 priority_queue<node >q;
 22 void calc_push(node u)
 23 {
 24     q.pop();
 25     q.push(u);
 26 }
 27 bool cmp(int a,int b){return val[a][opt]<val[b][opt];}
 28 void pushup(int u)
 29 {
 30     for(int i=0;i<2;++i)
 31     {
 32         L[u][i]=min(val[u][i],min(L[ls][i],L[rs][i]));
 33         R[u][i]=max(val[u][i],max(R[ls][i],R[rs][i]));
 34     }
 35 }
 36 void build(int &u,int l,int r,int k)
 37 {
 38     if(l>r)    return ;
 39     int mid=(l+r)>>1;    opt=k;
 40     sort(pos+l,pos+r+1,cmp);
 41     u=pos[mid];
 42     build(son[u][0],l,mid-1,k^1);
 43     build(son[u][1],mid+1,r,k^1);
 44     pushup(u);
 45 }
 46 ll dou(ll u)
 47 {
 48     return u*u;
 49 }
 50 void calc_point(int u)
 51 {
 52     num[u].dis=dou(x[0]-val[u][0])+dou(x[1]-val[u][1]);
 53 }
 54 void calc_KD(int u)
 55 {
 56     if(!u)    return ;
 57     ll a=max(dou(x[0]-L[u][0]),dou(x[0]-R[u][0]));
 58     ll b=max(dou(x[1]-L[u][1]),dou(x[1]-R[u][1]));
 59     num[u].dis=a+b;
 60 }
 61 void query(int u)
 62 {
 63     if(!u)    return ;
 64     calc_point(u);
 65     if(num[u]<q.top())    calc_push(num[u]);
 66     calc_KD(ls);
 67     calc_KD(rs);
 68     if(num[ls]<num[rs])
 69     {
 70         if(num[ls]<q.top())    query(ls);
 71         if(num[rs]<q.top())    query(rs);
 72     }
 73     else
 74     {
 75         if(num[rs]<q.top())    query(rs);
 76         if(num[ls]<q.top())    query(ls);
 77     }
 78 }
 79 int main()
 80 {
 81     L[0][0]=L[0][1]=inf;
 82     R[0][0]=R[0][1]=-inf;
 83     num[0].dis=-2;
 84     scanf("%d",&n);
 85     for(int i=1;i<=n;++i)
 86     {
 87         scanf("%lld%lld",&val[i][0],&val[i][1]);
 88         pos[i]=i;    num[i].pos=i;
 89     }
 90     build(root,1,n,0);
 91     scanf("%d",&m);
 92     while(m--)
 93     {
 94         scanf("%lld%lld%d",&x[0],&x[1],&n);
 95         while(!q.empty())    q.pop();
 96         while(n--)            q.push(node{inf,-1});
 97         query(root);
 98         printf("%d\n",q.top().pos);
 99     }
100     return 0;
101 }
View Code

 P4357 [CQOI2016]K远点对  一组询问,K 较大。

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define ls son[u][0]
 4 #define rs son[u][1]
 5 #define inf 1e9
 6 using namespace std;
 7 int n,m,root,opt;
 8 ll dis[100050];
 9 ll x[100050][2],y[2];
10 ll L[100050][2],R[100050][2];
11 int pos[100050];
12 int son[100050][2];
13 priority_queue<ll ,vector<ll>, greater<ll> >q;
14 bool cmp(int a,int b){return x[a][opt]<x[b][opt];}
15 void pushup(int u)
16 {
17     for(int i=0;i<2;++i)
18     {
19         L[u][i]=min(x[u][i],min(L[ls][i],L[rs][i]));
20         R[u][i]=max(x[u][i],max(R[ls][i],R[rs][i]));
21     }
22 }
23 void build(int &u,int l,int r,int k)
24 {
25     if(l>r)    return ;    opt=k;
26     sort(pos+l,pos+r+1,cmp);
27     int mid=(l+r)>>1;    u=pos[mid];
28     build(son[u][0],l,mid-1,k^1);
29     build(son[u][1],mid+1,r,k^1);
30     pushup(u);
31 }
32 ll dou(ll u)
33 {
34     return u*u;
35 }
36 void calc_point(int u)
37 {
38     dis[u]=dou(x[u][0]-y[0])+dou(x[u][1]-y[1]);
39 }
40 void calc_kd(int u)
41 {
42     if(!u)    return ;
43     ll a=max(dou(L[u][0]-y[0]),dou(R[u][0]-y[0]));
44     ll b=max(dou(L[u][1]-y[1]),dou(R[u][1]-y[1]));
45     dis[u]=a+b;
46 }
47 void query(int u)
48 {
49     if(!u)    return ;
50     calc_point(u);
51     if(dis[u]>q.top())
52     {
53         q.pop();
54         q.push(dis[u]);
55     }
56     calc_kd(ls);
57     calc_kd(rs);
58     if(dis[ls]>dis[rs])
59     {
60         if(dis[ls]>q.top())    query(ls);
61         if(dis[rs]>q.top())    query(rs);
62     }
63     else
64     {
65         if(dis[rs]>q.top())    query(rs);
66         if(dis[ls]>q.top())    query(ls);
67     }
68 }
69 int main()
70 {
71     L[0][0]=L[0][1]=inf;
72     R[0][0]=R[0][1]=-inf;
73     scanf("%d%d",&n,&m);m<<=1;
74     for(int i=1;i<=n;++i)
75     {
76         scanf("%lld%lld",&x[i][0],&x[i][1]);
77         pos[i]=i;
78     }
79     build(root,1,n,0);
80     while(m--)    q.push(0);
81     for(int i=n;i>=1;--i)
82     {
83         y[0]=x[i][0];
84         y[1]=x[i][1];
85         query(root);
86     }
87     printf("%lld",q.top());
88     return 0;
89 }
View Code

转载于:https://www.cnblogs.com/wyher/p/10434285.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值