• 扫描线求矩形面积并,使用线段树维护(感觉非常详细)


    HDOJ1542 Atlantis

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542

    题意:求平面中矩形面积并。

    这张图阴影和空白交替标出了并的面积。

    我是习惯从下向上扫描的。

    根据之前的一道CF EducationalRound的题,可以知道Ox坐标下扫描线的基本思路:

    “入”和“出”分别用-1和1来代替(但是这里需要在线段树中记录区间内边的条数,所以我把-1和1调换了位置,并且在cmp函数里修改了这个比较)

    但是平面的话,想记录每一列的宽度情况,所以可以用线段树来维护:线段树中的区间[l,r]代表[l,r]这个大区间有多长的子区间是被覆盖的。当然首先要离散化,不过存储这个覆盖的长度仍然是未离散化的长度。

    那么就会有类似于线段树中“区间合并”的问题了,但是这题很特殊,不需要区间合并

    特殊在哪里?

    一般的区间合并希望查询特定的[l,r]区间内被覆盖的子区间的总长度,但是这里不需要查询特定的[l,r]区间,而是整棵线段树描述的区间的覆盖总长度

    所以我们很轻易地想到,在update到一个需要覆盖的子区间的时候,向上传递这个子区间的长度。

    还会有一个问题:假如我在线段树上更新了一个表示区间[l,r]的节点rt,这个区间的父亲RT(假如表示区间[L, R],其中L<=l, r<=R)有没有可能被覆盖呢?

    这里就需要分情况讨论一下:

    1:RT表示的区间已经被完全覆盖过了

    2:RT表示的区间并没有被覆盖过,或者被覆盖了一部分

    对于情况1

    很好理解。在这个大区间下,由加了一条包含在[L,R]里的线段,类似这样:

    那我还需要使用[l,r]更新[L,R]的答案吗?很明显不需要。只需要用[L,R]代表的未离散化的长度更新一下当前值就行了。

    问题:为什么不用[l,r]更新[L,R],但是还要用未离散化的长度更新一下当前值?

    因为pushup操作不只是发生在发现小区间,还要在某区间的左右儿子均更新结束后,向上传第一次。

    对于情况2

    假如RT还没有覆盖过,或者覆盖了一部分:

    显然RT的覆盖部分是从左右儿子代表的子区间更新来的,那么直接用左右儿子的覆盖区间长度和更新就行。

    但是,假如RT代表的覆盖区间是一个点,即叶子的时候。显然一个点的区间长度是0,这点要注意特判一下。

    这样就没有问题了,顺便,感觉自己的离散化姿势很好。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define lrt rt << 1
     5 #define rrt rt << 1 | 1
     6 const int maxn = 210;
     7 typedef struct Seg {
     8     double len;
     9     int cnt;
    10 }Seg;
    11 typedef struct Event {
    12     double l, r, h;
    13     int sign;
    14 }Event;
    15 
    16 int n, hcnt;
    17 double h[maxn];
    18 vector<Event> event;
    19 Seg seg[maxn<<2];
    20 
    21 bool cmp(Event a, Event b) {
    22     if(a.h != b.h) return a.h < b.h;
    23     return a.sign > b.sign;
    24 }
    25 
    26 int id(double v) {
    27     return lower_bound(h, h+hcnt, v) - h + 1;
    28 }
    29 
    30 void build(int l, int r, int rt) {
    31     if(l == r) return;
    32     seg[rt].len = .0, seg[rt].cnt = 0;
    33     int mid = (l + r) >> 1;
    34     build(l, mid, lrt);
    35     build(mid+1, r, rrt);
    36 }
    37 
    38 void pushup(int l, int r, int rt) {
    39     if(seg[rt].cnt) seg[rt].len = h[r] - h[l-1];
    40     else {
    41         if(l == r) seg[rt].len = 0;
    42         else seg[rt].len = seg[lrt].len + seg[rrt].len;
    43     }
    44 }
    45 
    46 void update(int L, int R, int sign, int l, int r, int rt) {
    47     if(L <= l && r <= R) {
    48         seg[rt].cnt += sign;
    49         pushup(l, r, rt);
    50         return;
    51     }
    52     int mid = (l + r) >> 1;
    53     if(L <= mid) update(L, R, sign, l, mid, lrt);
    54     if(mid < R) update(L, R, sign, mid+1, r, rrt);
    55     pushup(l, r, rt);
    56 }
    57 
    58 int main() {
    59     // freopen("in", "r", stdin);
    60     int _ = 1;
    61     double ax, ay, bx, by;
    62     while(~scanf("%d", &n) && n) {
    63         event.clear(); hcnt = 0;
    64         for(int i = 0; i < n; i++) {
    65             scanf("%lf%lf%lf%lf",&ax,&ay,&bx,&by);
    66             event.push_back(Event{ax, bx, ay, 1});
    67             event.push_back(Event{ax, bx, by, -1});
    68             h[hcnt++] = ax; h[hcnt++] = bx;
    69         }
    70         sort(event.begin(), event.end(), cmp);
    71         sort(h, h+hcnt); hcnt = unique(h, h+hcnt) - h;
    72         build(1, hcnt, 1);
    73         double ret = .0;
    74         for(int i = 0; i < event.size(); i++) {
    75             int l = id(event[i].l);
    76             int r = id(event[i].r) - 1;
    77             int sign = event[i].sign;
    78             update(l, r, sign, 1, hcnt, 1);
    79             cout << event[i+1].h - event[i].h << endl;
    80             ret += (event[i+1].h - event[i].h) * seg[1].len;
    81         }
    82         printf("Test case #%d
    ", _++);
    83         printf("Total explored area: %.2f
    
    ", ret);
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    〖Linux〗秒开www.stackoverflow.com,非代理方式
    〖Linux〗git push orgin master不能解析域名的解决方法
    unity, terrain道出为obj
    unity, 顶点对齐
    world machine, 输出lightmap
    unity, scene视图查看场景时应调成正交模式
    unity, 由scriptableObject创建.asset
    unity, 播放循环背景音乐注意事项
    用audacity制作循环背景音乐
    unity, 保存prefab时material丢失问题
  • 原文地址:https://www.cnblogs.com/kirai/p/6807801.html
Copyright © 2020-2023  润新知