• 通过 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 ",q.top().pos); 99 } 100 return 0; 101 }
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 }