Codeforces Round #499 (Div. 1) E. Store[二维线段树]

题意

    有一个国家,他们每一年有 xmax x m a x 月,每月有 ymax y m a x 天,每天有 zmax z m a x 秒。这个国家的商店的时间表是这样排的:在一年中选出两个月: xl,xr(1xlxrxmax) x l , x r ( 1 ≤ x l ≤ x r ≤ x m a x ) ,在一个月中选出两天: yl,yr(1ylyrymax) y l , y r ( 1 ≤ y l ≤ y r ≤ y m a x ) ,在每天中选出两秒: zl,zr(1zlzrzmax) z l , z r ( 1 ≤ z l ≤ z r ≤ z m a x ) 。商店在第 x x 月,第y天,第 z z (xlxxr,ylyyr,zlzzr)会开门。现在有一个人,想去商店买东西,但是他并不知道准确的 xl,xr,yl,yr,zl,zr x l , x r , y l , y r , z l , z r ,他知道有 n(1n105) n ( 1 ≤ n ≤ 10 5 ) 个时间点,商店是开门的,有 m(1m105) m ( 1 ≤ m ≤ 10 5 ) 个时间点,商店是不开门的。
     (1) ( 1 ) 你的第一个任务是判断他的信息是否有错误,有错误输出INCORRECT,并跳过第二个任务;如果正确,输出CORRECT,继续执行第二个任务。
     (2) ( 2 ) 之后他给出 k(1k105) k ( 1 ≤ k ≤ 10 5 ) 个时间点,问你能不能确定这个时间点商店是否开门。如果开门,输出OPEN;如果不开门,输出CLOSE;如果不确定输出UNKNOWN。

分析

    这道题在比赛的时候并没有时间想,因为前面的题由于自己的智障花掉了太多时间。赛后想想发现其实也不是特别难。
    首先因为商店开门的时间其实可以转化为一个长方体,而知道商店开门的时间点就是在三维坐标系中位于这个长方体中的一个点,而商店关门的时间则是不在这个长方体中的一个点。询问就是给出一个点,问你这个点是否一定在长方形内部。
    我们先将原来给出的商店开门的时间构造成一个原长方体。对于一次询问,如果这个点在原长方体内,那么这个时间点商家一定是开门的。对于剩下的点,我们先将这个点假设为可以开门的点,那么我们可以扩大这个长方体。如果这个长方体扩大后发现没有任何一个关门的时间点在这个长方体内的话,那么是有可能开门的也有可能关门的,输出UNKNOWN。那么剩下的点就一定是关门的时间点了。这样可以将这个问题转化为三维数点的问题。对于这个问题我写的是二维线段树,然后里面那一维动态开点,然而应该也可以用KD-tree,或CDQ分治来做。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=100005,maxnode=16000005;
int mx,my,mz,n,m,k,lx,rx,ly,ry,lz,rz,cnt,lc[maxnode],rc[maxnode],lv[maxnode],rv[maxnode],rt[maxn<<2];
inline bool Open(int x,int y,int z) {
    return lx<=x&&x<=rx&&ly<=y&&y<=ry&&lz<=z&&z<=rz;
}
inline void update(int &o,int l,int r,int y,int z) {
    if(!o)
        o=++cnt,rv[o]=mz+1;
    if(lz<=z)
        rv[o]=min(rv[o],z);
    if(z<=rz)
        lv[o]=max(lv[o],z);
    if(l==r)
        return;
    int mid=(l+r)>>1;
    if(y<=mid)
        update(lc[o],l,mid,y,z);
    else
        update(rc[o],mid+1,r,y,z);
}
inline void modify(int o,int l,int r,int x,int y,int z) {
    update(rt[o],1,my,y,z);
    if(l==r)
        return;
    int mid=(l+r)>>1;
    if(x<=mid)
        modify(o<<1,l,mid,x,y,z);
    else
        modify(o<<1|1,mid+1,r,x,y,z);
}
inline bool getans(int o,int l,int r,int yl,int yr,int zl,int zr) {
    if(!o)
        return 1;
    if(yl<=l&&r<=yr)
        return lv[o]<zl&&zr<rv[o];
    bool res=1;
    int mid=(l+r)>>1;
    if(yl<=mid)
        res&=getans(lc[o],l,mid,yl,yr,zl,zr);
    if(yr>mid)
        res&=getans(rc[o],mid+1,r,yl,yr,zl,zr);
    return res;
}
inline bool query(int o,int l,int r,int xl,int xr,int yl,int yr,int zl,int zr) {
    if(xl<=l&&r<=xr)
        return getans(rt[o],1,my,yl,yr,zl,zr);
    bool res=1;
    int mid=(l+r)>>1;
    if(xl<=mid)
        res&=query(o<<1,l,mid,xl,xr,yl,yr,zl,zr);
    if(xr>mid)
        res&=query(o<<1|1,mid+1,r,xl,xr,yl,yr,zl,zr);
    return res;
}
inline void solve(int x,int y,int z) {
    if(Open(x,y,z))
        return (void)puts("OPEN");
    if(query(1,1,mx,min(lx,x),max(rx,x),min(ly,y),max(ry,y),min(lz,z),max(rz,z)))
        return (void)puts("UNKNOWN");
    return (void)puts("CLOSED");
}
int main() {
    read(mx),read(my),read(mz),read(n),read(m),read(k);
    lx=mx,ly=my,lz=mz;
    for(int i=1,x,y,z;i<=n;++i) {
        read(x),read(y),read(z);
        lx=min(lx,x),rx=max(rx,x);
        ly=min(ly,y),ry=max(ry,y);
        lz=min(lz,z),rz=max(rz,z);
    }
    for(int i=1,x,y,z;i<=m;++i) {
        read(x),read(y),read(z);
        if(Open(x,y,z))
            return 0*puts("INCORRECT");
        modify(1,1,mx,x,y,z);
    }
    puts("CORRECT");
    for(int i=1,x,y,z;i<=k;++i)
        read(x),read(y),read(z),solve(x,y,z); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值