[每日一题] 850. 矩形面积 II

120 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

850. 矩形面积 II

我们给出了一个(轴对齐的)二维矩形列表 rectangles 。我们给出了一个(轴对齐的)二维矩形列表 rectangles 。

对于 rectangle[i]=[x1,y1,x2,y2],其中(x1y1)是矩形 i 左下角的坐标,对于 rectangle[i] = [x_1, y_1, x_2, y_2],其中(x_1,y_1)是矩形 i 左下角的坐标,

 (xi1,yi1) 是该矩形左下角的坐标, (xi2,yi2) 是该矩形 右上角的坐标。 (xi_1, yi_1) 是该矩形 左下角 的坐标, (xi_2, yi_2) 是该矩形 右上角 的坐标。

计算平面中所有 rectangles 所覆盖的总面积。计算平面中所有 rectangles 所覆盖的 总面积 。

任何被两个或多个矩形覆盖的区域应只计算一次。任何被两个或多个矩形覆盖的区域应只计算 一次 。

返回总面积。因为答案可能太大,返回 109 +7的 模 。 返回 总面积 。因为答案可能太大,返回 10^9 + 7 的 模 。

示例 1:

image.png

输入:rectangles = [[0,0,2,2],[1,0,2,3],[1,0,3,1]]
输出:6
解释:如图所示,三个矩形覆盖了总面积为6的区域。
从(1,1)到(2,2),绿色矩形和红色矩形重叠。
从(1,0)到(2,3),三个矩形都重叠。

示例 2:

输入:rectangles = [[0,0,1000000000,1000000000]]
输出:49
解释:答案是 1018 对 (109 + 7) 取模的结果, 即 49

 

提示:

1 <= rectangles.length <= 200
rectanges[i].length = 4
0 <= xi1, yi1, xi2, yi2 <= 109
矩形叠加覆盖后的总面积不会超越 2^63 - 1 ,这意味着可以用一个 64 位有符号整数来保存面积结果。

思路

思路不难,主要是要去降低我们的时间复杂度
我们对于这种二维问题,可以找一个维度来维护,这个是可行的
那么,比如我们这一道题,我们可以选择x轴来进行计算,
当我们不看y轴时,对于每一根x轴形成的线就如同这种:

image.png

那么我们把一段区域的y轴给他连起来,类似于积分的思想,一块一块的累加起来以后
就类似于这种

image.png

对于每一部分来说,可以发现,在y轴上会形成2种状态,1种是覆盖,1种是空白
对于覆盖的位置来说,我们每次都要去累加计算这一部分的东西
前一时刻和后一时刻发生变化的位置 可以看出来,一定是矩形开始或者结束的位置(在y轴上)
维护一段线段的和用什么维护呢? 显然,用线段树可以做到 lognlog n 的求解 那么我们就可以利用这种扫描的思想,一路扫描过去,就知道了整体的面积 但是在扫描的时候,可以看出,由于我们的范围比较大,一单位一单位扫很显然浪费了
我们可以把y轴上,每一个矩形开始出现的线段和结束的线段给记录下来,用累加的思想来直接求解

对于y轴,我们已经解决了,我们还需要解决x轴上求和的问题,我们可以使用线段树
但是线段树的话,我们的值的范围很大,我们不可能直接存下来,
所以,我们需要离散化一下我们的x轴上的坐标
因为我们线段树维护时不关心真实的位置,我们只关心左右的关系,然后在计算真正长度时,做一个映射即可

代码

class segtree {
    struct node {
        int l, r;
        int tag, len;
    };
    vector<node> tr;
    vector<int>& mp;
    void pushup(int u) {
        if (tr[u].tag) tr[u].len = mp[tr[u].r] - mp[tr[u].l-1];
        else if(tr[u].l != tr[u].r) {
            tr[u].len = tr[u<<1].len + tr[u<<1|1].len;
        } else tr[u].len = 0;
    }
    void build(int u, int l, int r) {
        tr[u] = {l, r, 0, 0};
        if (l == r) return;
        int mid = (l + r) >> 1;
        build(u<<1, l, mid);
        build(u<<1|1, mid+1, r);
    }
public:
    segtree(int n, vector<int>& m):tr(n * 4 + 10), mp(m) {
        build(1, 1, n);
    }
    // @modify
    void modify(int u, int l, int r, int k) {
        if (l <= tr[u].l && tr[u].r <= r) {
            tr[u].tag += k;
            pushup(u);
            return;
        }
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u<<1, l, r, k);
        if (r > mid) modify(u<<1|1, l, r, k);
        pushup(u);
    }
    operator long long() {
        return tr[1].len;
    }
};

class Solution {
public:
    int rectangleArea(vector<vector<int>>& rectangles) {
        const int MOD = 1e9 + 7;
        struct E{int l, r, h, v;};
        vector<E> ve;
        vector<int> mp;
        for (auto v : rectangles) {
            ve.push_back({v[0], v[2], v[1], 1});
            ve.push_back({v[0], v[2], v[3], -1});
            mp.push_back(v[0]); // x1
            mp.push_back(v[2]); // x2
        }
        sort(ve.begin(), ve.end(), [](E& a, E& b) {
            return a.h < b.h;
        });
        sort(mp.begin(), mp.end());
        mp.erase(unique(mp.begin(), mp.end()), mp.end());
        auto find = [](vector<int>& mp, int val) {
            return lower_bound(begin(mp), end(mp), val) - begin(mp) + 1;
        };
        segtree seg(mp.size() - 1, mp);
        long long ans = 0;
        for (int i = 0; i < ve.size(); i ++) {
            if (i) ans += seg * (ve[i].h - ve[i-1].h);
            int l = find(mp, ve[i].l);
            int r = find(mp, ve[i].r);
            seg.modify(1, l, r-1, ve[i].v);
        }
        return ans % MOD;
    }
};