• 【HDU5126】 stars k-d树


    题目大意:有$m$个操作,分两种:在指定三维坐标内加入一个点,询问指定空间内点的数量。

    其中$m≤5*10^{4},1≤x,y,z≤10^9$

    这题几乎就是裸的$k-d$树啊。我们动态维护一棵$k-d$树,对于以某个节点为根的字树中,维护该子树中点的三维范围,以及该子树中点的数量。然后直接查询即可。

    PS:为了保证你的程序不会变成“优秀”的$n^{2}$做法,需要写一个类似虚树暴力重构的东西,去控制该树的平衡。

    #include<bits/stdc++.h>
    #define M 100000
    using namespace std;
    struct node{
        int a[3],max[3],min[3],sum,l,r,d;
        node(){
            a[0]=a[1]=a[2]=0; max[0]=max[1]=max[2]=0;
            min[0]=min[1]=min[2]=1234567890; sum=d=l=r=0;
        }
        node(int x,int y,int z){
            a[0]=x; a[1]=y; a[2]=z; sum=l=d=r=0;
            max[0]=max[1]=max[2]=0; min[0]=min[1]=min[2]=1234567890;
        }
        node(int x1,int y1,int z1,int x2,int y2,int z2){
            max[0]=x2; max[1]=y2; max[2]=z2;
            min[0]=x1; min[1]=y1; min[2]=z1;
            a[0]=a[1]=a[2]=sum=l=r=d=0;
        }
    }a[M]; int root=0,use=0;
    int id[M]={0},rebid=0,rebfa=0,now=0;
    void add(int &x,int fa,int d,node k){
        if(!x) x=++use,a[x]=k,a[x].d=d;
        else{
            if(k.a[d]<a[x].a[d]) add(a[x].l,x,(d+1)%3,k);
            else add(a[x].r,x,(d+1)%3,k);
        }
        a[x].max[0]=max(a[x].max[0],k.a[0]); a[x].min[0]=min(a[x].min[0],k.a[0]);
        a[x].max[1]=max(a[x].max[1],k.a[1]); a[x].min[1]=min(a[x].min[1],k.a[1]);
        a[x].max[2]=max(a[x].max[2],k.a[2]); a[x].min[2]=min(a[x].min[2],k.a[2]);
        a[x].sum++;
        if(max(a[a[x].l].sum,a[a[x].r].sum)>a[x].sum*0.7) rebid=x,rebfa=fa;
    }
    int D;
    bool cmp(int x,int y){
        return a[x].a[D]<a[y].a[D];
    }
    void bl(int x){
        if(!x) return; id[++now]=x;
        bl(a[x].l); bl(a[x].r);
        a[x].max[0]=a[x].max[1]=a[x].max[2]=a[x].l=a[x].r=a[x].sum=a[x].d=0;
        a[x].min[0]=a[x].min[1]=a[x].min[2]=1234567890;
    }
    void rebuild(int &x,int l,int r,int d){
        if(l>r) return; int mid=(l+r)>>1; D=d; 
        nth_element(id+l,id+mid,id+r+1,cmp); x=id[mid];
        rebuild(a[x].l,l,mid-1,(d+1)%3); rebuild(a[x].r,mid+1,r,(d+1)%3);
        for(int i=0;i<3;i++)
        a[x].max[i]=max(a[x].a[i],max(a[a[x].l].max[i],a[a[x].r].max[i])),
        a[x].min[i]=min(a[x].a[i],min(a[a[x].l].min[i],a[a[x].r].min[i]));
        a[x].sum=a[a[x].l].sum+a[a[x].r].sum+1; a[x].d=d;
    }
    void rebuild(){
        if(!rebid) return;
        bl(rebid); 
        if(rebfa==0) {rebuild(root,1,now,a[rebid].d);}
        else{
            if(a[rebfa].l==rebid) rebuild(a[rebfa].l,1,now,a[rebid].d);
            else rebuild(a[rebfa].r,1,now,a[rebid].d);    
        }
        rebid=rebfa=now=0;
    }
    int query(int x,node k){
        int ck=0,sum=0; if(!x) return 0;  
        for(int i=0;i<3;i++) if(k.min[i]<=a[x].min[i]&&a[x].max[i]<=k.max[i]) ck++; if(ck==3) return a[x].sum;
        for(int i=0;i<3;i++) if(k.max[i]<a[x].min[i]||a[x].max[i]<k.min[i]) return 0; ck=0;
        for(int i=0;i<3;i++) if(k.min[i]<=a[x].a[i]&&a[x].a[i]<=k.max[i]) ck++; if(ck==3) sum++;
        return sum+query(a[x].l,k)+query(a[x].r,k);
    }
    int main(){
        int n; scanf("%d",&n);
        while(n--){
            int op,x,y,z,x1,y1,z1; scanf("%d%d%d%d",&op,&x,&y,&z);
            if(op==1) add(root,0,0,node(x,y,z)),rebuild();
            else scanf("%d%d%d",&x1,&y1,&z1),printf("%d
    ",query(root,node(x,y,z,x1,y1,z1)));
        }
    }
  • 相关阅读:
    vs2017 项目调试浏览器网页闪退Bug
    “WebPageBase”在未引用的程序集中定义。必须添加对程序集“System.Web.WebPages, Version=1.0.0.0,Culture=neutral....."的引用
    SQL Server判断日期是否为周六 周日
    获取各国的日期时间
    .net Api项目初步搭建并移除XML格式
    鼠标滚轮事件
    js中if表达式判断规则
    原生轮播图
    C# uri
    SqlServer 备份还原教程
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/7944710.html
Copyright © 2020-2023  润新知