计蒜客 17313 Overlapping Rectangles

来源:互联网 发布:淘宝主图点击率怎么看 编辑:程序博客网 时间:2024/06/11 05:55

Problem

nanti.jisuanke.com/t/17313

Reference

扫描线算法完全解析
矩形面积并、矩形面积交、矩形周长并(线段树、扫描线总结)
POJ1151(线段树+扫描线求矩形面积并)
算法总结:【线段树+扫描线】&矩形覆盖求面积/周长问题(HDU 1542/HDU 1828)

Meaning

平面上有若干个矩形,可能有重叠,问总的面积是多少(重叠部分只算一次)

Analysis

这是扫描线求矩形面积并的裸题。
总的思路就是把几个重叠在一起的矩形所组成的多边形,切成一个个小矩形,分别统计答案。
split
以从下往上扫描为例(上图来自:poj 1151 Atlantis】线段树之扫描线(面积并))。关注矩形的上、下边,这些边(看作分界线)把平面分成若干个区间,每个区间都报包含一个切出来的小矩形。这个矩形的高,就是相邻两条分界线之间的距离,而底边长就是在当前扫描线(即上图红线)上的那些边并起来的长度(即处于红线上的矩形边的并),底乘高就是这块被切出来的小矩形的面积。
怎么统计扫描线上的总长度呢?用线段树。
在从下往上扫的过程中(扫描,其实就先是把所有矩形上、下边放到一起,按 y 轴坐标从低到高拍序,然后从低到高地遍历这些边,也即遍厉分界线),每遇到一条边,看它是上边还是下边。如果是下边,就把这条边“并”进总长里;上边则删掉这部分,即抵消到当初上边并进来的那部分。
这份代码里,线段树的叶子对应的是“点”,而不是“区间”,至少两个点才能夹出一个区间,所以当区间长度只有 2 的时候,不应再往下搜树。
也可以改写成叶子对应一个区间的写法。

Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 1000;struct seg{    int l, r; // 边的左、右边界坐标    int h; // 边的高度    int v; // 标记上下边:1 -> 下边,-1 -> 上边    seg(int _l = 0, int _r = 0, int _h = 0, int _v = 0):        l(_l), r(_r), h(_h), v(_v) {}    bool operator < (const seg &rhs) const    {        return h < rhs.h;    }} s[N<<1];int x[N<<1], cnt[N<<3], len[N<<3];void pushup(int l, int r, int rt){    if(cnt[rt])        len[rt] = x[r] - x[l];    else if(l + 1 >= r) // 已是最小区间,没有子区间        len[rt] = 0;    else        len[rt] = len[rt<<1] + len[rt<<1|1];}void update(int ul, int ur, int v, int l, int r, int rt){    if(ul <= l && r <= ur)    {        cnt[rt] += v;        pushup(l, r, rt);        return;    }    int m = l + r >> 1;    if(ul < m) // 等于的时候也是不需要的,因为一个点不是区间        update(ul, ur, v, l, m, rt<<1);    if(ur > m) // 同样不取等号        update(ul, ur, v, m, r, rt<<1|1); // [m,r]!不是[m+1,r]!    pushup(l, r, rt);}int main(){    int n;    while(~scanf("%d", &n) && n)    {        for(int i = 0, xl, xr, yl, yr; i < n; ++i)        {            scanf("%d%d%d%d", &xl, &yl, &xr, &yr);            // 下边是 1,表示并入            s[i] = seg(xl, xr, yl, 1);            // 下边-1,表示删除            s[i+n] = seg(xl, xr, yr, -1);            x[i] = xl;            x[i+n] = xr;        }        n <<= 1;        // 边从低到高排        sort(s, s + n);        sort(x, x + n);        memset(len, 0, sizeof len);        memset(cnt, 0, sizeof cnt);        int m = unique(x, x + n) - x, ans = 0;        for(int i = 0, l, r; i < n - 1; ++i)        {            // 离散化横坐标            l = lower_bound(x, x + m, s[i].l) - x;            r = lower_bound(x, x + m, s[i].r) - x;            // 并入或删除边            update(l, r, s[i].v, 0, m, 1);            // 加入小矩形面积            ans += len[1] * (s[i+1].h - s[i].h);        }        printf("%d\n", ans);    }    puts("*");    return 0;}
阅读全文
0 0
原创粉丝点击