zoukankan      html  css  js  c++  java
  • POJ 1151 Atlantis 线段树求矩形面积并 方法详解

    第一次做线段树扫描法的题,网搜各种讲解,发现大多数都讲得太过简洁,不是太容易理解。所以自己打算写一个详细的。看完必会o(∩_∩)o 

    顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中,这根线很重要。方向的话,可以左右扫,也可以上下扫。方法是一样的,这里我用的是由下向上的扫描法。

         

    如上图所示,坐标系内有两个矩形。位置分别由左下角和右上角顶点的坐标来给出。上下扫描法是对x轴建立线段树,矩形与y平行的两条边是没有用的,在这里直接去掉。如下图。

    现想象有一条线从最下面的边开始依次向上扫描。线段树用来维护当前覆盖在x轴上的线段的总长度,初始时总长度为0。用ret来保存矩形面积总和,初始时为0。

    由下往上扫描,扫描到矩形的底边时将它插入线段树,扫描到矩形的顶边时将底边从线段树中删除。而在代码中实现的方法就是,每条边都有一个flag变量,底边为1,顶边为-1。

    用cover数组(通过线段树维护)来表示某x轴坐标区间内是否有边覆盖,初始时全部为0。插入或删除操作直接让cover[] += flag。当cover[] > 0 时,该区间一定有边覆盖。

    开始扫描到第一条线,将它压入线段树,此时覆盖在x轴上的线段的总长度L为10。计算一下它与下一条将被扫描到的边的距离S(即两条线段的纵坐标之差,该例子里此时为3)。

                                                                                   则 ret += L * S. (例子里增量为10*3=30)

    结果如下图

      橙色区域表示已经计算出的面积。

    扫描到第二条边,将它压入线段树,计算出此时覆盖在x轴上的边的总长度。

    例子里此时L=15。与下一条将被扫描到的边的距离S=2。 ret += 30。 如下图所示。

    绿色区域为第二次面积的增量。

    接下来扫描到了下方矩形的顶边,从线段树中删除该矩形的底边,并计算接下来面积的增量。如下图。

     蓝色区域为面积的增量。

    此时矩形覆盖的总面积已经计算完成。 可以看到,当共有n条底边和顶边时,只需要从下往上扫描n-1条边即可计算出总面积。

    ==============================      分割线      ========================================

    此题因为横坐标包含浮点数,因此先离散化。另外,因为用线段树维护的是覆盖在x轴上的边,而边是连续的,并非是一个个断点,因此线段树的每一个叶子结点实际存储的是该点与下一点之间的距离。代码中r+1, r-1的地方多多体会。代码我是看着HH大神的代码写的,基本一样。在这里膜拜一下。。。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #define maxn 222
     5 #define lson l, m, rt << 1
     6 #define rson m + 1, r, rt << 1 | 1
     7 using namespace std;
     8 int cover[maxn<<2];
     9 double sum[maxn<<2], x[maxn];
    10 struct seg
    11 {
    12     double l, r, h;
    13     int flag;
    14     seg() {}
    15     seg(double a,double b,double c,int d) : l(a), r(b), h(c), flag(d) {}
    16     bool operator < (const seg &cmp) const
    17     {
    18         return h < cmp.h;
    19     }
    20 }ss[maxn];
    21 int bin(double key, int len, double x[])
    22 {
    23     int l = 0, r = len - 1;
    24     while (l <= r)
    25     {
    26         int m = (l + r) >> 1;
    27         if (key == x[m]) return m;
    28         else if (key < x[m]) r = m - 1;
    29         else l = m + 1;
    30     }
    31     return -1;
    32 }
    33 void PushUp(int rt,int l,int r)
    34 {
    35     if (cover[rt]) sum[rt] = x[r+1] - x[l];
    36     else if (l == r) sum[rt] = 0;
    37     else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    38 }
    39 void update(int L,int R,int f,int l,int r,int rt)
    40 {
    41     if (L <= l && r <= R)
    42     {
    43         cover[rt] += f;
    44         PushUp(rt, l, r);
    45         return;
    46     }
    47     int m = (l + r) >> 1;
    48     if (L <= m) update(L, R, f, lson);
    49     if (m < R) update(L, R, f, rson);
    50     PushUp(rt, l, r);
    51 }
    52 int main()
    53 {
    54     int n;
    55     int cas = 1;
    56     //freopen("data.in","r",stdin);
    57     while (~scanf("%d",&n) && n)
    58     {
    59         int m = 0;
    60         for (int i = 0; i < n; i++)
    61         {
    62             double x1,y1,x2,y2;
    63             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    64             x[m] = x1;
    65             ss[m++] = seg(x1, x2, y1, 1);
    66             x[m] = x2;
    67             ss[m++] = seg(x1, x2, y2, -1);
    68         }
    69         sort(x, x + m);
    70         sort(ss, ss + m);
    71         int k = 1;
    72         for (int i = 1; i < m; i++)
    73             if (x[i] != x[i-1]) x[k++] = x[i];
    74         memset(cover, 0, sizeof(cover));
    75         memset(sum, 0, sizeof(sum));
    76         double ret = 0;
    77         for (int i = 0; i < m - 1; i++)
    78         {
    79             int l = bin(ss[i].l, k, x);
    80             int r = bin(ss[i].r, k, x) - 1;
    81             if (l <= r) update(l, r, ss[i].flag, 0, k - 1, 1);
    82             ret += sum[1] * (ss[i+1].h - ss[i].h);
    83         }
    84         printf("Test case #%d
    Total explored area: %.2lf
    
    ",cas++,ret);
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    kendoui 时间选择框
    vue+webpack+win10搭建项目
    arcgis for javascript 自定义infowindow
    如何将 Microsoft Bot Framework 机器人部署以及网页应用
    STM32Cube_FW_F1_V1.0.0固件库学习(五) Systick
    STM32Cube_FW_F1_V1.0.0固件库学习(四)外部中断 下
    STM32Cube_FW_F1_V1.0.0固件库学习(四)外部中断 中
    STM32Cube_FW_F1_V1.0.0固件库学习(二)工程设置
    STM32Cube_FW_F1_V1.0.0固件库学习(四)中断概念 上
    STM32Cube_FW_F1_V1.0.0固件库学习(三)GPIO LED&KEY
  • 原文地址:https://www.cnblogs.com/fenshen371/p/3214092.html
Copyright © 2011-2022 走看看