1. 程式人生 > >bzoj 4237: 稻草人 -- CDQ分治

bzoj 4237: 稻草人 -- CDQ分治

pac amp upload 相同 truct gre 個數 tdi 左面

4237: 稻草人

Time Limit: 40 Sec Memory Limit: 256 MB

Description

JOI村有一片荒地,上面豎著N個稻草人,村民們每年多次在稻草人們的周圍舉行祭典。 有一次,JOI村的村長聽到了稻草人們的啟示,計劃在荒地中開墾一片田地。和啟示中的一樣,田地需要滿足以下條件: 田地的形狀是邊平行於坐標軸的長方形; 左下角和右上角各有一個稻草人; 田地的內部(不包括邊界)沒有稻草人。 給出每個稻草人的坐標,請你求出有多少遵從啟示的田地的個數

Input

第一行一個正整數N,代表稻草人的個數 接下來N行,第i行(1<=i<=N)包含2個由空格分隔的整數Xi和Yi,表示第i個稻草人的坐標

Output

輸出一行一個正整數,代表遵從啟示的田地的個數

Sample Input

4
0 0
2 2
3 4
4 3

Sample Output

3

HINT

所有滿足要求的田地由下圖所示:
技術分享圖片
1<=N<=2*10^5
0<=Xi<=10^9(1<=i<=N)
0<=Yi<=10^9(1<=i<=N)
Xi(1<=i<=N)互不相同。
Yi(1<=i<=N)互不相同。

Source

先將x軸排序,然後CDQ分治,這樣先保證左面x值一定小於右面

然後兩邊分別按y軸排序,然後去找合法解

我們可以左面維護x單調遞增的棧,右面維護x單調遞減的棧,這樣對於左面的每一位在右面二分查找就好

#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1000000007 #define ll long long #define N 200010 inline int rd() { 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; } int n; ll ans; struct qaz{int x,y;}a[N],b[N]; bool cmp(qaz a,qaz b){return a.x<b.x;} int q1[N],q2[N]; int fd(int x,int l,int r) { int mid; while(l+1<r) { mid=l+r>>1; if(a[q2[mid]].y<x) l=mid; else r=mid; } return l; } void cdq(int l,int r) { if(l==r) return; int mid=l+r>>1; cdq(l,mid);cdq(mid+1,r); int i,j=l,t1=0,t2=0; for(i=mid+1;i<=r;i++) { while(t1&&a[q1[t1]].x>a[i].x) t1--; q1[++t1]=i; for(;j<=mid&&a[j].y<a[i].y;j++) { while(t2&&a[q2[t2]].x<a[j].x) t2--; q2[++t2]=j; } ans+=t2-fd(a[q1[t1-1]].y,0,t2+1); } for(i=l,t1=l,t2=mid+1;i<=r;i++) b[i]=((t1<=mid&&a[t1].y<a[t2].y)||t2>r)?a[t1++]:a[t2++]; for(i=l;i<=r;i++) a[i]=b[i]; } int main() { n=rd(); for(int i=1;i<=n;i++) a[i].x=rd(),a[i].y=rd(); sort(a+1,a+n+1,cmp); cdq(1,n); printf("%lld\n",ans); return 0; }

bzoj 4237: 稻草人 -- CDQ分治