矩形面积并(扫描线)

思路:扫描线的思路很容易确定,但难点在于如何实现。这里避免写持久化标记,最初的想法是记录区间内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; }