bzoj 2648: SJY摆棋子

本文介绍了一种改进的 K-D Tree 数据结构,并详细解释了如何通过这种数据结构实现高效的最近邻搜索。该方法特别适用于处理大规模数据集,文中还提供了一个具体的实现案例,包括代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。

Solution

\(kdtree\)
比普通的 \(kdtree\) 差不多,多了一个插入操作,像平衡树一样插入就行了
这样可能会复杂度退化,可以使用定期重构的方法来稳定复杂度
实测加上定期重构之后反而变慢了,此题数据范围不宜这么做

#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
    int f;char c;
    for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=1e6+10,inf=1e9;
int n,D,Q,B,rt,cnt,ans,op;
struct data{
    int a[2],mn[2],mx[2],l,r;
    inline int& operator [](int x){return a[x];}
}t[N],e;
inline bool operator <(data p,data q){return p[D]<q[D];}
inline void upd(int o){
    int ls=t[o].l,rs=t[o].r;
    for(int i=0;i<2;i++){
        t[o].mx[i]=max(t[o].mx[i],max(t[ls].mx[i],t[rs].mx[i]));
        t[o].mn[i]=min(t[o].mn[i],min(t[ls].mn[i],t[rs].mn[i]));
    }
}
inline int build(int l,int r,int k){
    D=k;
    int mid=(l+r)>>1,o=mid;
    nth_element(t+l,t+mid,t+r+1);
    for(int i=0;i<2;i++)t[o].mx[i]=t[o].mn[i]=t[o][i];
    if(l<mid)t[o].l=build(l,mid-1,k^1);
    if(r>mid)t[o].r=build(mid+1,r,k^1);
    return upd(o),o;
}
inline int ins(int o,int k){
    if(!o)return cnt;
    if(e[k]>t[o][k])t[o].r=ins(t[o].r,k^1);
    else t[o].l=ins(t[o].l,k^1);
    return upd(o),o;
}
inline int dis(int o){return abs(t[o][0]-e[0])+abs(t[o][1]-e[1]);}
inline int cmin(int o){
    if(!o)return 0;
    int ret=0;
    for(int i=0;i<2;i++)ret+=max(0,e[i]-t[o].mx[i])+max(0,t[o].mn[i]-e[i]);
    return ret;
}
inline void qmin(int o){
    if(!o)return ;
    int dl=cmin(t[o].l),dr=cmin(t[o].r),dc=dis(o);
    ans=min(ans,dc);
    if(dl<dr){
        if(dl<ans)qmin(t[o].l);
        if(dr<ans)qmin(t[o].r);
    }
    else{
        if(dr<ans)qmin(t[o].r);
        if(dl<ans)qmin(t[o].l);
    }
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  cin>>n>>Q;B=sqrt(n+Q);cnt=n;
  for(int i=1;i<=n;i++)gi(t[i][0]),gi(t[i][1]);
  for(int i=0;i<=1;i++)t[0].mx[i]=-inf,t[0].mn[i]=inf;
  rt=build(1,n,0);
  while(Q--){
      gi(op);gi(e[0]);gi(e[1]);
      if(op==1){
          t[++cnt]=e;
          for(int i=0;i<2;i++)t[cnt].mx[i]=t[cnt].mn[i]=e[i];
          rt=ins(rt,0);
      }
      else ans=inf,qmin(rt),printf("%d\n",ans);
  }
  return 0;
}

转载于:https://www.cnblogs.com/Yuzao/p/9042904.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值