[LeeCode 391. 完美矩形]找规律+线段树扫描线

[LeeCode 391. 完美矩形]找规律+线段树扫描线

1. 题目链接

[LeeCode 391. 完美矩形]

2. 题意描述

题意描述

3. 解题思路

首先,完美矩形是一种精确覆盖.
有下面两条性质:

  1. 小矩形的面积之和等于大矩形的面积;
  2. 矩形不能重叠,也就是矩形最大覆盖数为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

猜你喜欢

转载自blog.csdn.net/ACMore_Xiong/article/details/81751094