BZOJ#4237. 稻草人
阿新 • • 發佈:2018-05-10
std 計劃 solved pri %d 發現 中間 包括 AC
Submit: 1483 Solved: 649
[Submit][Status][Discuss]
0 0
2 2
3 4
4 3
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)互不相同。
題目大意: 二維坐標系中給定了一些點,求兩兩組合構成矩形,滿足一個在右上角,一個在左下角,並且他們中間沒有其他點,求對數
分析: 二維偏序,考慮CDQ分治 我們分治時,先把y排序,分成上部分和下部分 再分別上下部分,按照x排序 現在我們的上部分的y都大於下部分的y 兩部分的x都是有序的 我們再用棧維護上部分的y遞增 用棧維護下部分的y遞減
附上代碼:
4237: 稻草人
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1483 Solved: 649
[Submit][Status][Discuss]
Description
JOI村有一片荒地,上面豎著N個稻草人,村民們每年多次在稻草人們的周圍舉行祭典。 有一次,JOI村的村長聽到了稻草人們的啟示,計劃在荒地中開墾一片田地。和啟示中的一樣,田地需要滿足以下條件: 田地的形狀是邊平行於坐標軸的長方形; 左下角和右上角各有一個稻草人; 田地的內部(不包括邊界)沒有稻草人。 給出每個稻草人的坐標,請你求出有多少遵從啟示的田地的個數
Input
第一行一個正整數N,代表稻草人的個數 接下來N行,第i行(1<=i<=N)包含2個由空格分隔的整數Xi和Yi,表示第i個稻草人的坐標
Output
輸出一行一個正整數,代表遵從啟示的田地的個數
Sample Input
40 0
2 2
3 4
4 3
Sample Output
3HINT
所有滿足要求的田地由下圖所示:
1<=N<=2*10^5
0<=Xi<=10^9(1<=i<=N)
Xi(1<=i<=N)互不相同。
Yi(1<=i<=N)互不相同。
題目大意: 二維坐標系中給定了一些點,求兩兩組合構成矩形,滿足一個在右上角,一個在左下角,並且他們中間沒有其他點,求對數
分析: 二維偏序,考慮CDQ分治 我們分治時,先把y排序,分成上部分和下部分 再分別上下部分,按照x排序 現在我們的上部分的y都大於下部分的y 兩部分的x都是有序的 我們再用棧維護上部分的y遞增 用棧維護下部分的y遞減
現在
這樣的 我們枚舉維護上部分
同時維護下部分 下部分x不超過當前上部分的x
比如上圖,我們上部分維護到了7
下部分也維護到了6
我們發現4之後的 下部分的棧裏面的數 都可以和7組成矩形 且中間沒有點
(因為我們維護了下部分遞減,所以中間不會再出現比他們小的數,有的話 5也會被彈出棧)
但是4前面的點,和7組成矩形,中間一定會有4,所以是不滿足的
所以我們就二分找出第一個x大於的下部分點
ans+=top2-res+1
加上這些點的個數就是答案了
現在我們就解決了 上下組合的問題
剩下的問題繼續CDQ分治解決
附上代碼:
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; struct node {int x,y;}d[N]; int n,stack1[N],top1,stack2[N],top2; long long ans=0; inline bool cmpy(node a,node b) {return a.y<b.y;} inline bool cmpx(node a,node b) {return a.x<b.x;} void CDQ(int l,int r) { if(l==r) return ; int mid=(l+r)>>1; top1=top2=0; sort(d+l,d+r+1,cmpy); sort(d+l,d+mid+1,cmpx); sort(d+mid+1,d+r+1,cmpx); int j=l; for(int i=mid+1;i<=r;i++) { while(top1&&d[stack1[top1]].y>=d[i].y) top1--;//上部分維護y遞增 stack1[++top1]=i; while(j<=mid&&d[j].x<d[i].x) { while(top2&&d[stack2[top2]].y<=d[j].y) top2--;//下部分維護y遞減 stack2[++top2]=j; m j++; } int st=d[stack1[top1-1]].x;//前面一個點的位置 int L=1,R=top2,res=-1; while(L<=R) { int mid=(L+R)>>1; if(d[stack2[mid]].x>st) res=mid,R=mid-1; else L=mid+1; } if(res!=-1) ans+=top2-res+1;//二分出來這個點 後面的點都滿足 } CDQ(l,mid);CDQ(mid+1,r); } int main() { freopen("a.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&d[i].x,&d[i].y); d[0].x=-1;d[0].y=-1; CDQ(1,n); printf("%lld\n",ans); return 0; }View Code
BZOJ#4237. 稻草人