C21 kd 树 P2479 [SDOI2010] 捉迷藏

视频链接:243 kd 树 [SDOI2010] 捉迷藏_哔哩哔哩_bilibili

 

Luogu P2479 [SDOI2010] 捉迷藏

复制代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define lc t[p].l
#define rc t[p].r
#define inf 0x3f3f3f3f
using namespace std;

const int N=100005;
int n,K,root,cur,ans1,ans2;
struct KD{  //KD树节点信息
  int l,r;  //左右孩子
  int v[2]; //点的坐标值
  int L[2],U[2]; //子树区域坐标范围
  bool operator<(const KD &b)const{return v[K]<b.v[K];}
}t[N];

void pushup(int p){ //更新p子树区域的坐标范围
  for(int i=0;i<2;i++){
    t[p].L[i]=t[p].U[i]=t[p].v[i];
    if(lc)
      t[p].L[i]=min(t[p].L[i],t[lc].L[i]),
      t[p].U[i]=max(t[p].U[i],t[lc].U[i]);
    if(rc)
      t[p].L[i]=min(t[p].L[i],t[rc].L[i]),
      t[p].U[i]=max(t[p].U[i],t[rc].U[i]);
  }
}
int build(int l,int r,int k){ //交替建树
  if(l>r) return 0;
  int m=(l+r)>>1; 
  K=k; nth_element(t+l,t+m,t+r+1); //中位数
  t[m].l=build(l,m-1,k^1);
  t[m].r=build(m+1,r,k^1);
  pushup(m);
  return m;
}
int dis(int p){ //当前点到p点的距离
  int s=0;
  for(int i=0;i<2;i++) 
    s+=abs(t[cur].v[i]-t[p].v[i]);
  return s;
}
int dis1(int p){ //当前点到p子树区域的最小距离
  if(!p) return inf;
  int s=0;
  for(int i=0;i<2;i++)
    s+=max(0,t[cur].v[i]-t[p].U[i])+
       max(0,t[p].L[i]-t[cur].v[i]);
  return s;
}
void query1(int p){ //查询最近距离
  if(!p) return;
  if(p!=cur) ans1=min(ans1,dis(p));
  int dl=dis1(lc), dr=dis1(rc);
  if(dl<dr){
    if(dl<ans1) query1(lc);
    if(dr<ans1) query1(rc);
  }
  else{
    if(dr<ans1) query1(rc);
    if(dl<ans1) query1(lc);
  }
}
int dis2(int p){ //当前点到p子树区域的最大距离
  if(!p) return 0;
  int s=0;
  for(int i=0;i<2;i++)
    s+=max(t[p].U[i]-t[cur].v[i], 
           t[cur].v[i]-t[p].L[i]);
  return s;
}
void query2(int p){ //查询最远距离
  if(!p) return;
  if(p!=cur) ans2=max(ans2, dis(p));
  int dl=dis2(lc), dr=dis2(rc);
  if(dl>dr){
    if(dl>ans2) query2(lc);
    if(dr>ans2) query2(rc);
  }
  else{
    if(dr>ans2) query2(rc);
    if(dl>ans2) query2(lc);
  }
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    scanf("%d%d",&t[i].v[0],&t[i].v[1]);
  root=build(1,n,0);
  int ans=inf;
  for(cur=1; cur<=n; cur++){
    ans1=inf, query1(root);
    ans2=0, query2(root);
    ans=min(ans,ans2-ans1);
  }
  printf("%d\n",ans);
}
复制代码

 

练习:

Luogu P6247 [SDOI2012] 最近最远点对 

 

posted @   董晓  阅读(143)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示