• 【BZOJ4237】稻草人 [分治][单调栈]


     稻草人

    Time Limit: 40 Sec  Memory Limit: 256 MB
    [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

    Sample Output

      3

    HINT

      1<=N<=2*10^5
      0<=Xi<=10^9(1<=i<=N), Xi(1<=i<=N)互不相同。
      0<=Yi<=10^9(1<=i<=N), Yi(1<=i<=N)互不相同。

    Solution

      O(n^2)做法很显然,既然这样,我们就使用惯用套路,我们先对 y 进行分治,将上面的点视为右上角的点下面的视为左下角的点,统计答案。
      首先把两部分的点分别按照 x 升序排序
      然后枚举上面的每个点
      显然,约束到它拓展的是 在它左下方最接近的点
      同时,下面的点最近的右上方点约束到点的拓展。

      那我们对于上面维护一个 y 递增单调栈,对下面维护一个 y 递减单调栈
      枚举到上面的点的时候,把 x 小于它的下面的点加入下面的那个单调栈,然后二分一下可行的位置就可以了。
      (显然,只有当下面的x > 上面单调栈倒数第二个点的 x 的时候 才可以被加入答案)

      (middle写成了mid调了一个小时!好气呀(╯‵□′)╯︵┻━┻)

    Code

     1 #include<iostream>
     2 #include<string>
     3 #include<algorithm>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cmath>
     8 #include<queue>
     9 using namespace std;
    10 typedef long long s64;
    11   
    12 const int ONE = 1000005;
    13  
    14 int get()
    15 {
    16         int res = 1, Q = 1; char c;
    17         while( (c = getchar()) < 48 || c > 57)
    18             if(c == '-') Q = -1;
    19         if(Q) res = c - 48;
    20         while( (c = getchar()) >= 48 && c <= 57)
    21             res = res * 10 + c - 48;
    22         return res * Q;
    23 }
    24  
    25 int n;
    26  
    27 struct point
    28 {
    29         int x, y;
    30 }a[ONE];
    31  
    32 bool cmpx(const point &a, const point &b) {return a.x < b.x;}
    33 bool cmpy(const point &a, const point &b) {return a.y < b.y;}
    34  
    35 int Stk_down[ONE], Stk_up[ONE];
    36 s64 Ans;
    37  
    38 void Solve(int l, int r)
    39 {
    40         if(l >= r) return;
    41         int mid = l + r >> 1;
    42          
    43         sort(a + l, a + r + 1, cmpy);
    44         sort(a + l, a + mid + 1, cmpx);
    45         sort(a + mid + 1, a + r + 1, cmpx);
    46          
    47         int top_up = 0, top_down = 0;
    48         int now = l;
    49          
    50         for(int i = mid + 1; i <= r; i++)
    51         {
    52             while(top_up > 0 && a[Stk_up[top_up]].y >= a[i].y) top_up--;
    53             Stk_up[++top_up] = i;
    54              
    55             while(now <= mid && a[now].x <= a[i].x)
    56             {
    57                 while(top_down > 0 && a[Stk_down[top_down]].y <= a[now].y) top_down--;
    58                 Stk_down[++top_down] = now;
    59                 now++;
    60             }
    61              
    62             int left = 1, right = top_down, pos = 0;
    63             int lx = top_up - 1 > 0 ? a[Stk_up[top_up - 1]].x : -1;
    64              
    65             while(left < right - 1)
    66             {
    67                 int middle = left + right >> 1;
    68                 if(a[Stk_down[middle]].x >= lx)
    69                     right = middle;
    70                 else
    71                     left = middle;
    72             }
    73              
    74              
    75             if(a[Stk_down[left]].x >= lx) pos = left;
    76             else
    77             if(a[Stk_down[right]].x >= lx) pos = right;
    78              
    79             if(pos) Ans += top_down - pos + 1;
    80         }
    81          
    82         Solve(l, mid), Solve(mid + 1, r);
    83 }
    84  
    85 int main()
    86 {
    87         n = get();
    88         for(int i = 1; i <= n; i++)
    89             a[i].x = get(), a[i].y = get();
    90          
    91         Solve(1, n);
    92         printf("%lld", Ans);
    93 }
    View Code
  • 相关阅读:
    第1周作业
    第0次作业
    第三周作业
    随笔1
    第一次作业
    第二周作业
    第零次作业
    第四周作业
    第三周作业
    第二次作业
  • 原文地址:https://www.cnblogs.com/BearChild/p/7784783.html
Copyright © 2020-2023  润新知