BZOJ 4237: 稻草人
4237: 稻草人
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 661 Solved: 286
[Submit][Status][Discuss]
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
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
将y这一维分治一下,每次考虑一个平面,中间割开,下面每个点作为左下点时,上面可以和其配对的右上点的个数。
将所有点按x维排序,扫描线从右向左,上面维护一个单调上升的栈,下面维护一个单调下降的栈,每次拿到下面一个点时,先在下面的栈中二分出第一个y大于它的点,这个点的x坐标是不可逾越的。然后二分出上面栈中有多少个点在这个界限以左,就是这个左下点的合法配对数。
UPDATE 2/18 补代码
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 template <class T> 8 __inline void read(T &x) 9 { 10 x = 0; 11 char c = getchar(); 12 while (c < 48)c = getchar(); 13 while (c > 47)x = x*10 + c - 48, c = getchar(); 14 } 15 16 #define rep(i,x,y) for(register int i=x;i<=y;++i) 17 #define per(i,x,y) for(register int i=x;i>=y;--i) 18 19 const int mxn = 2E5 + 5; 20 const int inf = 1E9 + 7; 21 22 int n; long long sum; 23 24 struct pii 25 { 26 int x, y; 27 }p[mxn]; 28 29 inline bool cmpX(const pii &a, const pii &b) 30 { 31 return a.x < b.x; 32 } 33 34 inline bool cmpY(const pii &a, const pii &b) 35 { 36 return a.y < b.y; 37 } 38 39 void solve(int l, int r) 40 { 41 if (l == r)return; 42 43 int m = (l + r) >> 1; 44 45 nth_element( 46 p + l, 47 p + m, 48 p + r + 1, 49 cmpY); 50 51 int h = p[m].y; 52 53 solve(l, m); 54 solve(m + 1, r); 55 56 static pii s[mxn]; 57 58 int t = 0, a = l, b = m + 1; 59 60 while (a <= m && b <= r) 61 { 62 if (p[a].x < p[b].x) 63 s[t++] = p[a++]; 64 else 65 s[t++] = p[b++]; 66 } 67 68 while (a <= m)s[t++] = p[a++]; 69 while (b <= r)s[t++] = p[b++]; 70 71 memcpy(p + l, s, t * sizeof(pii)); 72 73 static pii sa[mxn]; int ta = 0; 74 static pii sb[mxn]; int tb = 0; 75 76 per (i, r, l) 77 { 78 if (p[i].y > h) 79 { 80 while (ta && p[i].y < sa[ta].y)--ta; sa[++ta] = p[i]; 81 } 82 else 83 { 84 int ans = 0, lim = p[i].y; 85 86 { 87 int lt = 1, rt = tb, mid; 88 89 while (lt <= rt) 90 { 91 mid = (lt + rt) >> 1; 92 93 if (sb[mid].y > lim) 94 lt = mid + 1, ans = mid; 95 else 96 rt = mid - 1; 97 } 98 } 99 100 if (ans) 101 lim = sb[ans].x; 102 else 103 lim = inf; 104 105 ans = 0; 106 107 { 108 int lt = 1, rt = ta, mid; 109 110 while (lt <= rt) 111 { 112 mid = (lt + rt) >> 1; 113 114 if (sa[mid].x > lim) 115 lt = mid + 1, ans = mid; 116 else 117 rt = mid - 1; 118 } 119 } 120 121 sum += ta - ans; 122 123 while (tb && p[i].y > sb[tb].y)--tb; sb[++tb] = p[i]; 124 } 125 } 126 } 127 128 signed main(void) 129 { 130 read(n); 131 132 rep (i, 1, n) 133 read(p[i].x), 134 read(p[i].y); 135 136 sort(p + 1, p + n + 1, cmpX); rep (i, 1, n)p[i].x = i; 137 sort(p + 1, p + n + 1, cmpY); rep (i, 1, n)p[i].y = i; 138 139 solve(1, n), printf("%lld\n", sum); 140 }
@Author: YouSiki