[bzoj1941]k-d tree 模板

本文介绍了K-D树的数据结构实现及其在最近邻搜索中的应用。通过递归划分空间来组织数据点,实现了高效的范围查询和最近邻查找。文中详细展示了如何使用C++进行K-D树的构建和维护,包括节点更新、距离计算等关键步骤。

w_yqts 的指导下学习了kdtree……
http://blog.csdn.net/silangquan/article/details/41483689
听说这东西很优秀……Orz
但看起来就像一个暴力剪枝.

#include <cstdio>
#include <algorithm>
using namespace std;
#define inf 1000000000
#define N 500005
#define K 2
inline int read()
{
    char ch=getchar();
    int x=0,f=1;
    while ('0'>ch || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while ('0'<=ch && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
int kd,rt,nx,mx;
int n,ans;
struct node
{
    int l,r,n[K],m[K];
}tr[N];
struct KD
{
    int k[K];
}a[N];
inline int dis(const KD x,const KD y)
{
    int res=0;
    for (int i=0;i<K;++i) res+=abs(x.k[i]-y.k[i]);
    return res;
}
bool cmp(KD x,KD y)
{
    return x.k[kd]<y.k[kd];
}
inline void update(int x)
{
    int l=tr[x].l,r=tr[x].r;
    for (int i=0;i<K;++i)
    {
        tr[x].n[i]=tr[x].m[i]=a[x].k[i];
        if (l) tr[x].n[i]=min(tr[x].n[i],tr[l].n[i]);
        if (r) tr[x].n[i]=min(tr[x].n[i],tr[r].n[i]);
        if (l) tr[x].m[i]=max(tr[x].m[i],tr[l].m[i]);
        if (r) tr[x].m[i]=max(tr[x].m[i],tr[r].m[i]);
    }
}
int build(int l,int r)
{
    if (l>r) return 0;
    int mid=(l+r)>>1;
    nth_element(a+l,a+mid,a+1+r,cmp);
    for (int i=0;i<K;++i) tr[mid].n[i]=tr[mid].m[i]=a[mid].k[i];
    if (l==r) return l;
    kd^=1;
    tr[mid].l=build(l,mid-1);
    tr[mid].r=build(mid+1,r);
    kd^=1;
    update(mid);
    return mid;
}
inline int getnx(int x,const KD t)
{
    int dis=0;
    for (int i=0;i<K;++i)
    dis+=max(t.k[i]-tr[x].m[i],0)+max(tr[x].n[i]-t.k[i],0);
    return dis;
}
inline int getmx(int x,const KD t)
{
    int dis=0;
    for (int i=0;i<K;++i) dis+=max(abs(t.k[i]-tr[x].n[i]),abs(t.k[i]-tr[x].m[i]));
    return dis;
}
void querynx(int x,const KD t)
{
    int tmp=dis(a[x],t);
    if (tmp) nx=min(nx,tmp);
    int l=tr[x].l,r=tr[x].r,disl=inf,disr=inf;
    if (l) disl=getnx(l,t);
    if (r) disr=getnx(r,t);
    if (disl<disr)
    {
        if (disl<nx) querynx(l,t);
        if (disr<nx) querynx(r,t);
    }else
    {
        if (disr<nx) querynx(r,t);
        if (disl<nx) querynx(l,t);
    }
}
void querymx(int x,const KD t)
{
    int tmp=dis(a[x],t);
    mx=max(mx,tmp);
    int l=tr[x].l,r=tr[x].r,disl=-inf,disr=-inf;
    if (l) disl=getmx(l,t);
    if (r) disr=getmx(r,t);
    if (disl>disr)
    {
        if (disl>mx) querymx(l,t);
        if (disr>mx) querymx(r,t);
    }else
    {
        if (disr>mx) querymx(r,t);
        if (disl>mx) querymx(l,t);
    }
}
inline void solve(const KD x)
{
    nx=inf,mx=-inf;
    querynx(rt,x);
    querymx(rt,x);
    ans=min(ans,mx-nx);
}
int main()
{
    n=read();
    for (int i=1;i<=n;++i) for (int k=0;k<K;++k) a[i].k[k]=read();
    rt=build(1,n);
    ans=inf;
    for (int i=1;i<=n;++i) solve(a[i]);
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值