矩形面积并(扫描线)

 

 思路:扫描线的思路很容易确定,但难点在于如何实现。这里避免写持久化标记,最初的想法是记录区间内0的个数(即未覆盖点的个数),但是如此一来每一次更新都需要将tag下放到最底层才能完全更新(因为对于每一个数,只有将所有tag完全作用于这个数时才能知道这个数到底会不会变为0);同时我们这一题还需要进行离散化,所以本身上就不可能对整个点做到维护。

作为替换思路,我们选择维护区间最小值以及区间最小值的个数(当区间最小值为0时代表该区间中存在未覆盖点)这是可以维护的。同时要注意一些细节,比如因为我们线段树维护的是一段,所以离散化下标要进行处理

 

 

 

 

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
int n, m, mp[2 * N];
vector<array<int, 4>> event;
vector<int> vx;
struct info {
    int minv, mincnt;
};

info operator +(const info& l, const info& r) {
    info a;
    a.minv = min(l.minv, r.minv);
    if (l.minv == r.minv) a.mincnt = l.mincnt + r.mincnt;
    else if (l.minv > r.minv)a.mincnt = r.mincnt;
    else a.mincnt = l.mincnt;
    return a;
}

struct node {
    int t;//tag
    info val;//区间最小值,区间最小值个数
}seg[N * 8];//一个矩形最多带来两个离散点,所以还要*2

void update(int id) {
    seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}

void settag(int id, int t) {//打上标记
    seg[id].val.minv += t;
    seg[id].t += t;
}

void build(int id, int l, int r) {
    if (l == r) {
        seg[id].val = { 0,vx[r] - vx[r - 1]};//最小值,长度
    }
    else {
        int mid = (l + r) / 2;
        build(id * 2, l, mid);
        build(id * 2 + 1, mid + 1, r);
        update(id);
    }
}

void pushdown(int id) {
    if (seg[id].t != 0) {
        settag(id * 2, seg[id].t);
        settag(id * 2 + 1, seg[id].t);
        seg[id].t = 0;
    }
}
void modify(int id, int l, int r, int ql, int qr, int t) {
    if (l == ql && r == qr) {
        settag(id, t);
        return;
    }
    int mid = (l + r) >> 1;
    pushdown(id);
    if (qr <= mid) modify(id * 2, l, mid, ql, qr, t);
    else if (ql > mid) modify(id * 2 + 1, mid + 1, r, ql, qr, t);
    else {
        modify(id * 2, l, mid, ql, mid, t);
        modify(id * 2 + 1, mid + 1, r, mid + 1, qr, t);
    }
    update(id);
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int x1, x2, y1, y2;
        scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
        vx.push_back(x1);
        vx.push_back(x2);
        event.push_back({ y1,1,x1,x2 });
        event.push_back({ y2,-1,x1,x2 });
    }
    sort(event.begin(), event.end());
    sort(vx.begin(), vx.end());
    vx.erase(unique(vx.begin(), vx.end()), vx.end());
    m = vx.size() - 1;//m段
    build(1, 1, m);
    int totlen = seg[1].val.mincnt;
    int prey = 0;
    ll ans = 0;
    for (auto evt : event) {
        int cov = totlen;
        if (seg[1].val.minv == 0)    cov = totlen - seg[1].val.mincnt;//还有覆盖
        ans += (ll)(evt[0] - prey) * cov;
        prey = evt[0];
        int x1 = lower_bound(vx.begin(), vx.end(), evt[2]) - vx.begin() + 1;//x1+1
        int x2 = lower_bound(vx.begin(), vx.end(), evt[3]) - vx.begin();//x2+1-1
        if (x1 > x2) continue;//空矩形
        modify(1, 1, m, x1, x2, evt[1]);
    }
    printf("%lld\n", ans);
    return 0;
}

 

posted @ 2022-09-20 19:47  Aacaod  阅读(26)  评论(0编辑  收藏  举报