BZOJ2648&&2716 不讲道理的KD-tree

本文探讨了KDTree在二维空间中的应用,并分享了一个具体的实现案例。通过对比重建树的操作前后效果,发现去除重建步骤能有效提升效率。文章提供了一段简洁高效的C++代码示例,展示了如何构建和查询KDTree。

不得不承认KDtree的却是二维空间类距离处理利器,省去了树套树繁琐的操作,code简洁明了。

为了防止KDtree我还特意加上了rebuild的操作……结果反而更满了……,cnt太小<=70000还会TLE……WCO

哎,KDTREE就那样吧,随便打打,开心开心就好了。

//去掉rebuild操作更快。
#include<bits/stdc++.h>
inline int maxn(int x,int y){return x<y?y:x;}
inline int minn(int x,int y){return x<y?x:y;}
int n,m,root,cmp_d,k1,k2,k3,ans;
struct node{
    int d[2],l,r,maxn[2],minn[2];
}tree[1000001],pte[1000001],tmp;
inline bool cmp(node a,node b){
    return (a.d[cmp_d]<b.d[cmp_d])||
    ((a.d[cmp_d]==b.d[cmp_d])&&(a.d[!cmp_d]<b.d[!cmp_d]));
}
void update(const int p){
    if(tree[p].l){
        if(tree[p].maxn[0]<tree[tree[p].l].maxn[0])tree[p].maxn[0]=tree[tree[p].l].maxn[0];
        if(tree[p].minn[0]>tree[tree[p].l].minn[0])tree[p].minn[0]=tree[tree[p].l].minn[0];
        if(tree[p].maxn[1]<tree[tree[p].l].maxn[1])tree[p].maxn[1]=tree[tree[p].l].maxn[1];
        if(tree[p].minn[1]>tree[tree[p].l].minn[1])tree[p].minn[1]=tree[tree[p].l].minn[1];
    }if(tree[p].r){
        if(tree[p].maxn[0]<tree[tree[p].r].maxn[0])tree[p].maxn[0]=tree[tree[p].r].maxn[0];
        if(tree[p].minn[0]>tree[tree[p].r].minn[0])tree[p].minn[0]=tree[tree[p].r].minn[0];
        if(tree[p].maxn[1]<tree[tree[p].r].maxn[1])tree[p].maxn[1]=tree[tree[p].r].maxn[1];
        if(tree[p].minn[1]>tree[tree[p].r].minn[1])tree[p].minn[1]=tree[tree[p].r].minn[1];
    }
}
int build(const int l,const int r,const int D){
    if(l>r)return 0;
    register int mid=(l+r)>>1;
    cmp_d=D;std::nth_element(pte+l+1,pte+mid+1,pte+r+1,cmp);
    tree[mid]=pte[mid];
    tree[mid].maxn[0]=tree[mid].minn[0]=tree[mid].d[0];
    tree[mid].maxn[1]=tree[mid].minn[1]=tree[mid].d[1];
    tree[mid].l=build(l,mid-1,!D);
    tree[mid].r=build(mid+1,r,!D);
    update(mid);
    return mid;
}
inline void insert(const int now){
    register int D,p;
    D=0;p=root;
    while(1){
        if(tree[now].maxn[0]>tree[p].maxn[0])tree[p].maxn[0]=tree[now].maxn[0];
        if(tree[now].maxn[1]>tree[p].maxn[1])tree[p].maxn[1]=tree[now].maxn[1];
        if(tree[now].minn[0]<tree[p].minn[0])tree[p].minn[0]=tree[now].minn[0];
        if(tree[now].minn[1]<tree[p].minn[1])tree[p].minn[1]=tree[now].minn[1];
        if(tree[now].d[D]>=tree[p].d[D]){
            if(tree[p].r==0){
                tree[p].r=now;
                return;
            }else p=tree[p].r;
        }else{
            if(tree[p].l==0){
                tree[p].l=now;
                return;
            }else p=tree[p].l;
        }
        D=!D;
    }
}
inline int dist(const int p1,const int px,const int py){
    register int dis=0;
    if(px<tree[p1].minn[0])dis+=tree[p1].minn[0]-px;
    if(px>tree[p1].maxn[0])dis+=px-tree[p1].maxn[0];
    if(py<tree[p1].minn[1])dis+=tree[p1].minn[1]-py;
    if(py>tree[p1].maxn[1])dis+=py-tree[p1].maxn[1];
    return dis;
}
inline void query(const int p){
    register int dl,dr,d0;
    d0=abs(tree[p].d[0]-k2)+abs(tree[p].d[1]-k3);
    if(d0<ans)ans=d0;
    if(tree[p].l)dl=dist(tree[p].l,k2,k3);else dl=0x7f7f7f7f;
    if(tree[p].r)dr=dist(tree[p].r,k2,k3);else dr=0x7f7f7f7f;
    if(dl<dr){
        if(dl<ans)query(tree[p].l);
        if(dr<ans)query(tree[p].r);
    }else{
        if(dr<ans)query(tree[p].r);
        if(dl<ans)query(tree[p].l);
    }
}
template<class T>inline void read(T &res){
    static char ch;T flag=1;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
    while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
int main(){
    read(n),read(m);
    register int i,j,cnt=0;
    tree[0].maxn[0]=tree[0].maxn[1]=-0x7f7f7f7f;
    tree[0].minn[0]=tree[0].minn[1]= 0x7f7f7f7f;
    for(i=1;i<=n;++i)read(pte[i].d[0]),read(pte[i].d[1]);
    root=build(1,n,0);
    for(i=1;i<=m;++i){
        read(k1),read(k2),read(k3);
        if(k1==1){
            ++n;
            tree[n].maxn[0]=tree[n].minn[0]=tree[n].d[0]=k2;
            tree[n].maxn[1]=tree[n].minn[1]=tree[n].d[1]=k3;
            insert(n);
            if(++cnt==200000){
                for(j=1;j<=n;j++)pte[j]=tree[j];
                root=build(1,n,0);cnt=0;
            }
        }else{
            ans=0x7f7f7f7f;
            query(root);
            printf("%d\n",ans); 
        }   
    }
    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值