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 x1−1,0 y1−1,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);
}