本文已参与「新人创作礼」活动,一起开启掘金创作之路。
850. 矩形面积 II
示例 1:
输入: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轴形成的线就如同这种:
那么我们把一段区域的y轴给他连起来,类似于积分的思想,一块一块的累加起来以后
就类似于这种
对于每一部分来说,可以发现,在y轴上会形成2种状态,1种是覆盖,1种是空白
对于覆盖的位置来说,我们每次都要去累加计算这一部分的东西
前一时刻和后一时刻发生变化的位置 可以看出来,一定是矩形开始或者结束的位置(在y轴上)
维护一段线段的和用什么维护呢? 显然,用线段树可以做到 的求解 那么我们就可以利用这种扫描的思想,一路扫描过去,就知道了整体的面积 但是在扫描的时候,可以看出,由于我们的范围比较大,一单位一单位扫很显然浪费了
我们可以把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;
}
};