[LeeCode 391. 完美矩形]找规律+线段树扫描线
程序员文章站
2022-03-21 07:50:18
...
[LeeCode 391. 完美矩形]找规律+线段树扫描线
1. 题目链接
2. 题意描述
3. 解题思路
首先,完美矩形是一种精确覆盖.
有下面两条性质:
- 小矩形的面积之和等于大矩形的面积;
- 矩形不能重叠,也就是矩形最大覆盖数为1.
而且,很容易证明,满足上述两条性质,就一定是完美矩形.
对于第一条性质,只需要求出大矩形的边界就好了;
对于第二条性质,是一个线段树扫描线求矩形最大覆盖数的经典题. 具体做法,将横坐标离散化,然后将矩形拆分成上下两条线段, 将线段按照高度从小到大排序, 依次添加到线段树中(线段树保存的各个坐标当前覆盖的次数,下边界区间加法, 上边界区间减法).然后就可以统计出矩形的最大覆盖数了.
4. 参考代码
#ifdef __LOCAL_WONZY__
#include <bits/stdc++.h>
using namespace std;
#endif
class Solution {
public:
typedef long long ll;
static const int inf = 0x3f3f3f3f;
struct Line {
int le, ri, h, t;
Line() {}
Line(int le, int ri, int h, int t) : le(le), ri(ri), h(h), t(t) {}
bool operator < (const Line& e) const {
if(h == e.h) return t < e.t;
return h < e.h;
}
};
vector<int> fr, fc;
vector<int> seg, tag;
int rhash(int x) {
return lower_bound(fr.begin(), fr.end(), x) - fr.begin();
}
int chash(int x) {
return lower_bound(fc.begin(), fc.end(), x) - fc.begin();
}
void pushDw(int rt, int w) {
if(!tag[rt]) {
seg[rt << 1] += tag[rt];
seg[rt << 1 | 1] += tag[rt];
tag[rt << 1] += tag[rt];
tag[rt << 1 | 1] += tag[rt];
tag[rt] = 0;
}
}
void pushUp(int rt) {
seg[rt] = max(seg[rt << 1], seg[rt << 1 | 1]);
}
void update(const int L, const int R, const int val, int le, int ri, int rt) {
if(L <= le && ri <= R) {
seg[rt] += val;
tag[rt] += val;
return;
}
pushDw(rt, ri - le + 1);
int md = (le + ri) >> 1;
if(L <= md) update(L, R, val, le, md, rt << 1);
if(R > md) update(L, R, val, md + 1, ri, rt << 1 | 1);
pushUp(rt);
}
bool isRectangleCover(vector<vector<int>>& rectangles) {
vector<Line> lines;
long long area = 0;
vector<int> d = {inf, inf, -inf, -inf};
for(auto& e : rectangles) {
fr.push_back(e[0]); //fc.push_back(e[1]);
fr.push_back(e[2]); //fc.push_back(e[3]);
fr.push_back(e[0] - 1);
fr.push_back(e[2] - 1);
d[0] = min(d[0], e[0]); d[1] = min(d[1], e[1]);
d[2] = max(d[2], e[2]); d[3] = max(d[3], e[3]);
lines.push_back(Line(e[0], e[2], e[1], +1));
lines.push_back(Line(e[0], e[2], e[3], -1));
area += (e[2] - e[0]) * (e[3] - e[1]);
}
if(area != (long long)(d[2] - d[0]) * (d[3] - d[1])) return false;
sort(fr.begin(), fr.end());
//sort(fc.begin(), fc.end());
fr.erase(unique(fr.begin(), fr.end()), fr.end());
//fc.erase(unique(fc.begin(), fc.end()), fc.end());
sort(lines.begin(), lines.end());
int m = fr.size();
seg = tag = vector<int>(m << 2, 0);
int mval = 0;
for(auto& e : lines) {
int lpos = rhash(e.le), rpos = rhash(e.ri - 1);
update(lpos, rpos, e.t, 0, m - 1, 1);
mval = max(mval, seg[1]);
}
return mval <= 1;
}
};
#ifdef __LOCAL_WONZY__
int main() {
#ifdef __LOCAL_WONZY__
freopen("input-1.txt", "r", stdin);
#endif
vector<vector<int>> a = {
{1,1,3,3},
{3,1,4,2},
{3,2,4,4},
{1,3,2,4},
{2,3,3,4},
};
vector<vector<int>> b = {
{1,1,2,3},
{1,3,2,4},
{3,1,4,2},
{3,2,4,4},
};
vector<vector<int>> c = {
{1,1,3,3},
{3,1,4,2},
{1,3,2,4},
{2,2,4,4},
};
Solution s;
cout << s.isRectangleCover(c) << endl;;
return 0;
}
#endif
下一篇: 洛谷 P1044 栈