[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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章