zoukankan      html  css  js  c++  java
  • bzoj 4237 稻草人

    题目传送门

      传送点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 }
  • 相关阅读:
    第一个win8应用的制作过程
    win8开发-Xaml学习笔记一
    梦想成为“老板”的第二天
    梦想成为“老板”的第一天
    HTTP请求
    linux常用命令
    HTML中常用的标签
    HTML基本结构
    记录Django的settings文件常用配置
    Oracle数据泵expdp、impdp
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9433436.html
Copyright © 2011-2022 走看看