考虑枚举左下角这个点。然后看一下是个什么情况:
嗯对,是个单调栈。但不可能暴力去求每个点右侧和上方的点的单调栈。
注意到如果给单调栈设个上界,那么顶多会削掉一些点,不会发生大的改变。
考虑CDQ分治,然后按照$y$从大到小排序。枚举左边的点然后不断把右边纵坐标大于它的点加入单调栈。(把横坐标比它大的全弹掉)
然后还需要考虑一个问题:
绿色点上方的点不能选。
如何找到这个上界?对左边开一个单调栈。然后在单调栈上二分。然后在右边的单调栈上二分可以找到有多少点不能选。
(今天考这道题,怀疑自己是zz,左边写一个线段树找上界,右边二分了两次)
Code
1 /** 2 * bzoj 3 * Problem#4237 4 * Accepted 5 * Time: 7540ms 6 * Memory: 8332k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <ctime> 13 #ifndef WIN32 14 #define Auto "%lld" 15 #else 16 #define Auto "%I64d" 17 #endif 18 using namespace std; 19 typedef bool boolean; 20 #define ll long long 21 const signed int inf = (signed) (~0u >> 1); 22 23 typedef class IO { 24 public: 25 int sta; 26 27 }IO; 28 29 int __tp = 30; 30 char __buf[30]; 31 32 #define digit(_x) ((_x) >= '0' && (_x) <= '9') 33 #define pick(_x) ((_x) = getchar()) 34 35 IO& operator >> (IO& io, int& u) { 36 char x; 37 while (~(x = getchar()) && !digit(x)); 38 for (u = x - '0'; x = getchar(), digit(x); u = u * 10 + x - '0'); 39 return io; 40 } 41 42 IO in; 43 44 template<typename T> 45 void alloc(T*& p, int siz) { 46 p = new T[(siz + 1)]; 47 } 48 49 typedef class Point { 50 public: 51 int x, y; 52 53 boolean operator < (Point b) const { 54 if (y ^ b.y) return y > b.y; 55 return x < b.x; 56 } 57 }Point; 58 59 int n; 60 ll res = 0; 61 int *buf; 62 Point *ps, *bp; 63 Point *pt, *vt; 64 65 inline void init() { 66 in >> n; 67 alloc(vt, n); 68 alloc(ps, n), alloc(bp, n); 69 alloc(buf, n), alloc(pt, n); 70 for (int i = 1; i <= n; i++) 71 in >> ps[i].x >> ps[i].y; 72 } 73 74 inline void discrete() { 75 for (int i = 1; i <= n; i++) 76 buf[i] = ps[i].x; 77 sort(buf + 1, buf + n + 1); 78 for (int i = 1; i <= n; i++) 79 ps[i].x = lower_bound(buf + 1, buf + n + 1, ps[i].x) - buf; 80 for (int i = 1; i <= n; i++) 81 buf[i] = ps[i].y; 82 sort(buf + 1, buf + n + 1); 83 for (int i = 1; i <= n; i++) 84 ps[i].y = lower_bound(buf + 1, buf + n + 1, ps[i].y) - buf; 85 } 86 87 int search(Point* pt, int tp, int y) { 88 int l = 1, r = tp; 89 while (l <= r) { 90 int mid = (l + r) >> 1; 91 if (pt[mid].y <= y) 92 r = mid - 1; 93 else 94 l = mid + 1; 95 } 96 return r + 1; 97 } 98 99 void dividing(int l, int r, int ql, int qr) { 100 if (l == r || ql > qr) 101 return ; 102 int mid = (l + r) >> 1; 103 int pl = l - 1, pr = r + 1; 104 for (int i = ql; i <= qr; i++) 105 if (ps[i].x <= mid) 106 bp[++pl] = ps[i]; 107 else 108 bp[--pr] = ps[i]; 109 reverse(bp + pr, bp + qr + 1); 110 for (int i = ql; i <= qr; i++) 111 ps[i] = bp[i]; 112 113 int tp = 0, tp1 = 1; 114 vt[1] = (Point) {inf, inf}; 115 for (int i = l; i <= pl; i++) { 116 while (pr <= r && ps[pr].y > ps[i].y) { 117 while (tp && pt[tp].x >= ps[pr].x) 118 tp--; 119 pt[++tp] = ps[pr], pr++; 120 } 121 int l = 1, r = tp1; 122 while (l <= r) { 123 int mid = (l + r) >> 1; 124 if (vt[mid].x >= ps[i].x) 125 l = mid + 1; 126 else 127 r = mid - 1; 128 } 129 res += tp - search(pt, tp, vt[l - 1].y) + 1; 130 while (tp1 && vt[tp1].x <= ps[i].x) 131 tp1--; 132 vt[++tp1] = ps[i]; 133 } 134 135 dividing(l, mid, ql, pl); 136 dividing(mid + 1, r, pl + 1, qr); 137 } 138 139 inline void solve() { 140 sort(ps + 1, ps + n + 1); 141 dividing(1, n, 1, n); 142 printf(Auto, res); 143 } 144 145 int main() { 146 init(); 147 discrete(); 148 solve(); 149 return 0; 150 }