[bzoj1790][Ahoi2008]Rectangle 矩形藏宝地

1790: [Ahoi2008]Rectangle 矩形藏宝地

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 393 Solved: 129
[Submit][Status][Discuss]
Description

欢乐岛上最著名的游戏是一个寻宝游戏,小可可来到宝藏的埋藏地,这是一块开阔地,宝藏被分散的埋藏在这块地下,现在要做的是一件件的把宝藏挖出来。为了提示宝藏的埋藏点,游戏的主办方把这块开阔地当作第一象限,将所有可能埋藏宝藏的地方划成一个个矩形的土地,并把这些矩形土地的坐标都告诉了参赛者。挖宝的提示很简单,只要某一个矩阵土地至少被另外一个矩阵土地所包含,那么这个矩阵土地里肯定埋有宝藏。其实这些宝藏都是一些精美的纪念品,如果谁挖出来了纪念品就归谁了,小可可很想为这次旅程画上完美的句号,有你的帮助他信心十足,你只要告诉他.有多少个矩形土地里肯定埋有宝藏就行了。胜利就在眼前,加油吧!!
Input

第一行包含一个整数N(N≤200000),表示矩形的个数。接下来N行,每行用4个整数x1,y1,x2,y2,描述了一个矩形。其中(x1,y1)表示这个矩形左下角的坐标,(x2,y2)表示右上角的坐标,一个xi值或yi值最多出现一次.
Output

只包含一个整数,表示肯定埋有宝藏的矩形土地的个数。
Sample Input

3

0 0 5 5

1 2 3 4

2 1 4 3

Sample Output

2

HINT

100%的数据中,N<=200000
70%的数据申,N<=50000
30%的数据中,N<=5000
所有数据中,一个x值或Y值最多出现一次

每一个二维的平面可以用两个点来表示。 kd 树不能处理这种包含的问题。那就可以吧这个平面转化一下。
两个点表示的平面需要四个坐标,那么我们随便拿出三个来,比如说选 (x1,y1,x2)(x1<x2,y1<y2) y2 表示这个点权值,那么每次就是相当于查询 (0 x11,0 y11,x2 max) 的最大值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200010;
int n,root,D,ans,lim,now,va;
struct S{
    int l,r,d[3],mi[3],ma[3],v,maxn;
    int &operator [](int x){
        return d[x];
    }
    bool operator < (const S &x)const{
        return d[D]<x.d[D]; 
    }
}tr[N],p[N];
inline int IN(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void update(int k){
    int l=tr[k].l,r=tr[k].r,i;
    tr[k].maxn=max(tr[k].v,max(tr[l].maxn,tr[r].maxn));
    for(i=0;i<=2;++i){
        tr[k].mi[i]=tr[k].ma[i]=tr[k][i];
        if(l){
            tr[k].mi[i]=min(tr[k].mi[i],tr[l].mi[i]);
            tr[k].ma[i]=max(tr[k].ma[i],tr[l].ma[i]);
        }
        if(r){
            tr[k].mi[i]=min(tr[k].mi[i],tr[r].mi[i]);
            tr[k].ma[i]=max(tr[k].ma[i],tr[r].ma[i]);
        }
    }
}
#define mid (l+r)/2
inline int build(int l,int r,int flag){
    if(l>r) return 0;
    D=flag;nth_element(p+l,p+mid,p+r+1);
    tr[mid]=p[mid];
    tr[mid].l=build(l,mid-1,(flag+1)%3);
    tr[mid].r=build(mid+1,r,(flag+1)%3);
    update(mid);
    return mid;
}
inline bool in(int k,int x1,int y1,int x2,int y2,int x3,int y3){
    return tr[k].mi[0]>=x1&&tr[k].ma[0]<=y1&&tr[k].mi[1]>=x2&&tr[k].ma[1]<=y2&&tr[k].mi[2]>=x3&&tr[k].ma[2]<=y3;
}
inline bool out(int k,int x1,int y1,int x2,int y2,int x3,int y3){
    return tr[k].mi[0]>y1||tr[k].ma[0]<x1||tr[k].mi[1]>y2||tr[k].ma[1]<x2||tr[k].mi[2]>y3||tr[k].ma[2]<x3;
}
inline bool in1(int k,int x1,int y1,int x2,int y2,int x3,int y3){
    return tr[k][0]>=x1&&tr[k][0]<=y1&&tr[k][1]>=x2&&tr[k][1]<=y2&&tr[k][2]>=x3&&tr[k][2]<=y3;
}
inline void query(int k,int x1,int y1,int x2,int y2,int x3,int y3){
    if(now>va) return ;
    if(x1>y1||x2>y2||x3>y3||!k) return ;
    if(in(k,x1,y1,x2,y2,x3,y3)){
        now=max(now,tr[k].maxn);
        return ;
    }
    if(out(k,x1,y1,x2,y2,x3,y3)) return ;
    if(in1(k,x1,y1,x2,y2,x3,y3)) now=max(now,tr[k].v);
    if(tr[tr[k].l].maxn>va) query(tr[k].l,x1,y1,x2,y2,x3,y3);
    if(tr[tr[k].r].maxn>va) query(tr[k].r,x1,y1,x2,y2,x3,y3);
}
int main(){
    int i,x1,x2,y1,y2,j;
    n=IN();
    for(i=1;i<=n;++i){
        x1=IN();y1=IN();x2=IN();y2=IN();
        lim=max(lim,x2);
        p[i][0]=x1;p[i][1]=y1,p[i][2]=x2;
        p[i].v=p[i].maxn=y2;
        for(j=0;j<=2;++j)
          p[i].mi[j]=p[i].ma[j]=p[i][j];
    }
    root=build(1,n,0);
    for(i=1;i<=n;++i){
        now=0;va=p[i].v;
        query(root,0,p[i][0]-1,0,p[i][1]-1,p[i][2],lim);
        ans+=(now>p[i].v);
    }
    printf("%d\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值