4066: 简单题 K-D tree重构

本文分享了一种使用K-D树解决数据查询问题的方法,并在树不平衡时采用暴力重构策略来确保查询效率。通过示例代码详细介绍了节点结构、树构建、插入、查询等关键步骤。

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

sb错误调了两个小时。。。
其实就是K-D tree,然后在不太平衡的时候就暴力重构一下。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define inf 1000000007
using namespace std;
int cunt;
struct node
{
    int d[2],mn[2],mx[2];
    int size,sum,v,D;
};
node now,tree[N];
int ls[N],rs[N],p[N];
int n,w,D,root,tot,cnt,ans;
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}/*
inline bool cmp(node a,node b)
{
    return a.d[D]<b.d[D];
}*/ // 就是这里写错了。。。坑啊。。
inline bool cmp(int a,int b)    
{
    return tree[a].d[D]<tree[b].d[D];
}
inline void pushup(int k)
{
    for (int i=0;i<=1;i++)
    {
        tree[k].mn[i]=min(tree[k].mn[i],min(tree[ls[k]].mn[i],tree[rs[k]].mn[i]));
        tree[k].mx[i]=max(tree[k].mx[i],max(tree[ls[k]].mx[i],tree[rs[k]].mx[i]));
    }
    tree[k].sum=tree[ls[k]].sum+tree[rs[k]].sum+tree[k].v;
    tree[k].size=tree[ls[k]].size+tree[rs[k]].size+1;
}
int build(int &k,int l,int r,int dir)
{
    int mid=l+r>>1; D=dir;
    nth_element(p+l,p+mid,p+r+1,cmp);
    k=p[mid];
    tree[k].D=dir;
    tree[k].mn[0]=tree[k].mx[0]=tree[k].d[0];
    tree[k].mn[1]=tree[k].mx[1]=tree[k].d[1];
    tree[k].sum=tree[k].v;
    if (l<mid) build(ls[k],l,mid-1,dir^1); else ls[k]=0;
    if (r>mid) build(rs[k],mid+1,r,dir^1); else rs[k]=0;
    pushup(k);
}
void dfs(int k)
{
    if (!k) return;
    dfs(ls[k]); p[++tot]=k; dfs(rs[k]);
}
inline void rebuild(int &k)
{
    tot=0; dfs(k);
    build(k,1,tot,tree[k].D);
}
void insert(int &k,int dir)
{
    if (!k)
    {
        k=++cnt;
        tree[k]=now;
        tree[k].mn[0]=tree[k].mx[0]=tree[k].d[0];
        tree[k].mn[1]=tree[k].mx[1]=tree[k].d[1];
        tree[k].sum=tree[k].v; tree[k].size=1;
        tree[k].D=dir;
        return;
    }
    if (now.d[dir]<tree[k].d[dir])
    {
        insert(ls[k],dir^1);
        pushup(k);
        if ((double)tree[ls[k]].size>(double)tree[k].size*0.7) rebuild(k);
    }
    else
    {
        insert(rs[k],dir^1);
        pushup(k);
        if ((double)tree[rs[k]].size>(double)tree[k].size*0.7) rebuild(k);
    }
}
int query(int k,int x1,int y1,int x2,int y2)
{
    cunt ++ ;
    if (!k) return 0;
    int ans=0;
    if (tree[k].mn[0]>=x1&&tree[k].mx[0]<=x2&&tree[k].mn[1]>=y1&&tree[k].mx[1]<=y2) return tree[k].sum;
    else
    {
        if (tree[k].d[0]>=x1&&tree[k].d[0]<=x2&&tree[k].d[1]>=y1&&tree[k].d[1]<=y2) ans+=tree[k].v;
        if (tree[ls[k]].mn[0]>x2||tree[ls[k]].mx[0]<x1||tree[ls[k]].mn[1]>y2||tree[ls[k]].mx[1]<y1); else ans+=query(ls[k],x1,y1,x2,y2);
        if (tree[rs[k]].mn[0]>x2||tree[rs[k]].mx[0]<x1||tree[rs[k]].mn[1]>y2||tree[rs[k]].mx[1]<y1); else ans+=query(rs[k],x1,y1,x2,y2);
        return ans;
    }
}
int main()
{
//  freopen("txt.in","r",stdin);
//  freopen("1.out","w",stdout);
    tree[0].mn[0]=tree[0].mn[1]=inf;
    tree[0].mx[0]=tree[0].mx[1]=-inf;
    n=read();
    while (scanf("%d",&w)!=EOF&&w!=3)
        if (w==1)
        {
            now.d[0]=read()^ans; now.d[1]=read()^ans; now.v=read()^ans;
//          now.d[0]=read(); now.d[1]=read(); now.v=read();
            insert(root,1);
        }
        else
        {
            int x1=read()^ans,y1=read()^ans,x2=read()^ans,y2=read()^ans;
//          int x1=read(),y1=read(),x2=read(),y2=read();
            printf("%d\n",ans=query(root,x1,y1,x2,y2));
        }
//  for (int k=1;k<=10;k++)
//      printf("%d %d %d %d %d %d\n",tree[k].sum,tree[k].D,tree[k].mx[0],tree[k].mx[1],tree[k].mn[0],tree[k].mn[1]);
    cout << cunt;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值