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值最多出現一次
每一個二維的平面可以用兩個點來表示。
兩個點表示的平面需要四個座標,那麼我們隨便拿出三個來,比如說選
#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);
}