bzoj 4237 稻草人 - CDQ分治 - 单调栈

题目传送门

  传送点I

  传送点II

题目大意

  平面上有$n$个点。问存在多少个矩形使得只有左下角和右上角有点。

  考虑枚举左下角这个点。然后看一下是个什么情况:

  嗯对,是个单调栈。但不可能暴力去求每个点右侧和上方的点的单调栈。

  注意到如果给单调栈设个上界,那么顶多会削掉一些点,不会发生大的改变。

  考虑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 }
posted @ 2018-08-06 21:28  阿波罗2003  阅读(1033)  评论(0编辑  收藏  举报