【KD树】Codeforces499Div1 CF1010E Store

题意:

在一个三维空间中,存在一个长方体,但并不知道它的具体位置,但有n个点在长方体内,m个点不在长方体内,先判断是否合法,若合法再给出k组询问,每次询问某个点是否在长方体内(回答在,不在,或不确定)


分析:

诶。。这次B、C题被hack了,不然就有时间做这题了。。。。想哭

其实这题也不难。

首先根据n个在长方体内的点,确定长方体每个维度坐标的最小值&最大值。

如果一个点满足 xminxxmaxyminyymaxzminzzmax x m i n ≤ x ≤ x m a x 且 y m i n ≤ y ≤ y m a x 且 z m i n ≤ z ≤ z m a x ,那么其必然在长方体内。

先通过这个判断那m个点是否合法。

然后把这m个点存起来。

对于每次询问,如果满足一定在长方体内的条件,直接输出。

否则先假设它在长方体内,并通过它得到一个新的 xmin,xmax,ymin,ymax,zmin,zmax x m i n , x m a x , y m i n , y m a x , z m i n , z m a x

然后判断这个新的范围是否会让那m个点中的任意一个非法。

如果合法(即新的范围内仍然没有m中的点),那么答案就是不确定

如果非法(即新的范围中有m中的点),答案就是不存在长方体中。

当然,每次询问后范围都要恢复。

具体实现。。。用KD树就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
struct node{
    int minx[4],maxx[4],d[4];
    int l,r;
    update(const node &a){
        for(int i=0;i<3;i++){
            minx[i]=min(minx[i],a.minx[i]);
            maxx[i]=max(maxx[i],a.maxx[i]);
        }
    }
}t[MAXN];
int D;
bool cmp(const node& a,const node &b){
    if(a.d[D]!=b.d[D])
        return a.d[D]<b.d[D];
    if(a.d[(D+1)%3]!=b.d[(D+1)%3])
        return a.d[(D+1)%3]<b.d[(D+1)%3];
    return a.d[(D+2)%3]<b.d[(D+2)%3];
}
int build(int l,int r,int nowd){
    int mid=(l+r)>>1;
    D=nowd;
    nth_element(t+l,t+mid,t+r+1,cmp);
    for(int i=0;i<3;i++)
        t[mid].maxx[i]=t[mid].minx[i]=t[mid].d[i];
    if(l<mid){
        t[mid].l=build(l,mid-1,(nowd+1)%3);
        t[mid].update(t[t[mid].l]);
    }
    if(r>mid){
        t[mid].r=build(mid+1,r,(nowd+1)%3);
        t[mid].update(t[t[mid].r]);
    }
    return mid;
}
int minval[4],maxval[4];
bool check_intersect(int l1,int r1,int l2,int r2){
    if(l1>r2||l2>r1)
        return 0;
    return 1;
}
bool check_intersect(const node &a){
    for(int i=0;i<3;i++)
        if(check_intersect(a.minx[i],a.maxx[i],minval[i],maxval[i])==0)
            return 0;
    return 1;
}
bool check_contain(int l1,int r1,int l2,int r2){
    if(l2<=l1&&r1<=r2)
        return 1;
    return 0;
}
bool check_contain(const node &a){
    for(int i=0;i<3;i++)
        if(check_contain(a.minx[i],a.maxx[i],minval[i],maxval[i])==0)
            return 0;
    return 1;   
}
bool query(int x){
    if(x==0)
        return 0;
    if(check_intersect(t[x])==0)
        return 0;
    if(check_contain(t[x]))
        return 1;
    if(minval[0]<=t[x].d[0]&&t[x].d[0]<=maxval[0]&&minval[1]<=t[x].d[1]&&t[x].d[1]<=maxval[1]&&minval[2]<=t[x].d[2]&&t[x].d[2]<=maxval[2])
        return 1;
    if(query(t[x].l))
        return 1;
    if(query(t[x].r))
        return 1;
    return 0;
}
int minx,miny,minz,maxx,maxy,maxz;
int main(){
    int n,m,k;
    int x,y,z;
    SF("%d%d%d%d%d%d",&x,&y,&z,&n,&m,&k);
    minx=x;
    miny=y;
    minz=z;
    maxx=1;
    maxy=1;
    maxz=1;
    for(int i=1;i<=n;i++){
        SF("%d%d%d",&x,&y,&z);
        minx=min(minx,x);
        miny=min(miny,y);
        minz=min(minz,z);
        maxx=max(maxx,x);
        maxy=max(maxy,y);
        maxz=max(maxz,z);
    }
    int tot=0;
    for(int i=1;i<=m;i++){
        SF("%d%d%d",&x,&y,&z);
        if(minx<=x&&x<=maxx&&miny<=y&&y<=maxy&&minz<=z&&z<=maxz){
            PF("INCORRECT");
            return 0;
        }
        tot++;
        t[tot].d[0]=x;
        t[tot].d[1]=y;
        t[tot].d[2]=z;
    }
    PF("CORRECT\n");
    int rt=build(1,tot,0);
    for(int i=1;i<=k;i++){
        SF("%d%d%d",&x,&y,&z);
        if(minx<=x&&x<=maxx&&miny<=y&&y<=maxy&&minz<=z&&z<=maxz){
            PF("OPEN\n");
        }
        else{
            minval[0]=min(minx,x);
            minval[1]=min(miny,y);
            minval[2]=min(minz,z);
            maxval[0]=max(maxx,x);
            maxval[1]=max(maxy,y);
            maxval[2]=max(maxz,z);
            if(query(rt))
                PF("CLOSED\n");
            else
                PF("UNKNOWN\n");    
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值