HDOJ 3265 Posters(扫描线 + 线段树 矩形面积的并)

题意:

给定N(N <= 50000)个中空的矩形纸片,求它们面积并。

思路:

1. 和前面一个矩形面积的并区别之处在于,这次是存在一个镂空的矩形,所以要切割成 4 个。

2. 前面我尝试了一种不切割的方法,即只处理 4 根扫描线,结果证明这个思路是很麻烦的,因为扫描线是成对增加,成对消去,这样的话就制造了不必要的麻烦。

3. 边界问题,越界问题,都要注意 sum[1] * (seg[i+1].h - seg[i].h) 这句话用 int 是会溢出的,所以当我改成 unsigned int 就 AC 了。

#include <iostream>
#include <algorithm>
using namespace std;

#define lhs l, m, rt << 1
#define rhs m + 1, r, rt << 1 | 1

const int maxn = 200010;
unsigned int sum[maxn << 2], cnt[maxn << 2];

struct Segment {
    unsigned int l, r, h, v;
    Segment() { }

    Segment(int _l, int _r, int _h, int _v) : 
    l(_l), r(_r), h(_h), v(_v) { }

    bool operator < (const Segment& other) 
    { 
        if (h == other.h)
            return v > other.v;
        else
            return h < other.h; 
    }
} seg[maxn << 1] ;

void PushUp(int l, int r, int rt)
{
    if (cnt[rt])
        sum[rt] = r - l + 1;
    else if (l == r)
        sum[rt] = 0;
    else
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void Update(int beg, int end, int value, int l, int r, int rt)
{
    if (beg <= l && r <= end)
    {
        cnt[rt] += value;
        PushUp(l, r, rt);
        return ;
    }

    int m = (l + r) >> 1;
    if (beg <= m)
        Update(beg, end, value, lhs);
    if (end > m)
        Update(beg, end, value, rhs);
    PushUp(l, r, rt);
}

int main()
{
    int n;
    while (scanf("%d", &n) && n)
    {
        int m = 0;
        int beg = 50000, end = 0;
        for (int i = 0; i < n; ++i)
        {
            int a, b, c, d;
            int a1, b1, c1, d1;

            scanf("%d %d %d %d", &a, &b, &c, &d);
            scanf("%d %d %d %d", &a1, &b1, &c1, &d1);

            beg = min(beg, a);
            end = max(end, c);

            seg[m++] = Segment(a, a1, b, 1);
            seg[m++] = Segment(a, a1, d, -1);

            seg[m++] = Segment(a1, c1, b, 1);
            seg[m++] = Segment(a1, c1, b1, -1);

            seg[m++] = Segment(a1, c1, d1, 1);
            seg[m++] = Segment(a1, c1, d, -1);

            seg[m++] = Segment(c1, c, b, 1);
            seg[m++] = Segment(c1, c, d, -1);
        }
        sort(seg, seg + m);

        memset(sum, 0, sizeof(sum));
        memset(cnt, 0, sizeof(cnt));

        __int64 ret = 0;
        for (int i = 0; i < m - 1; ++i)
        {
            if (seg[i].l < seg[i].r)
                Update(seg[i].l, seg[i].r - 1, seg[i].v, beg, end - 1, 1);
            ret += (__int64)(sum[1] * (seg[i+1].h - seg[i].h));
        }
        printf("%I64d\n", ret);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/2890170.html