【模板】扫描线
题目描述
求 n 个四边平行于坐标轴的矩形的面积并。
输入格式
第一行一个正整数 n。
接下来 𝑛n 行每行四个非负整数x1,y1,x2,y2,表示一个矩形的四个端点坐标为 (𝑥1,𝑦1),(𝑥1,𝑦2),(𝑥2,𝑦2),(𝑥2,𝑦1)。
think: 维护一个带懒标记的线段树
struct node {
int l, r; //左右端点
int minv, cnt; //区间最小值,区间最小值出现的次数
int tag; //懒标记.本题特殊情况只支持区间+1, -1.
}tr[N * 8];
由于本题四边形边界会到1e9,所以还需要离散化,这里就离散化x坐标了(也可以离散化y坐标)
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
find用来查询离散化后下标对应的值
int find(int y)
{
return lower_bound(alls.begin(), alls.end(), y) - alls.begin() + 1;
}
最后,讲一下为什么可以这样做,我们每次查询tr[1]这个区间,如果这个区间的最小值不是0,说明整个区间都被覆盖了.反之,当前区间被覆盖的长度就是区间长度-当前区间最小值的个数.
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define int long long
const int N = 1e6 + 10;
typedef pair<int, int> pii;
int n, m;
vector<int> alls;
vector<array<int, 4>> event;
struct node {
int l, r;
int minv, cnt;
int tag;
}tr[N * 8];
int find(int y)
{
return lower_bound(alls.begin(), alls.end(), y) - alls.begin() + 1;
}
void pushup(node &root, node &l, node &r) {
if (l.minv == r.minv) {
root.cnt = l.cnt + r.cnt;
root.minv = l.minv;
} else if (l.minv < r.minv) {
root.cnt = l.cnt;
root.minv = l.minv;
} else {
root.cnt = r.cnt;
root.minv = r.minv;
}
}
void pushup(int u) {
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void build(int u, int l, int r) {
if (l == r) {
tr[u] = {l, r, 0, alls[r] - alls[l - 1], 0};
return;
} else {
tr[u] = {l, r, 0, 0, 0};
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void pushdown(int u) {
if (tr[u].tag) {
tr[u << 1].tag += tr[u].tag;
tr[u << 1 | 1].tag += tr[u].tag;
tr[u << 1].minv += tr[u].tag;
tr[u << 1 | 1].minv += tr[u].tag;
tr[u].tag = 0;
}
}
void modify(int u, int l, int r, int v) {
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].minv += v;
tr[u].tag += v;
} else {
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (r <= mid) modify(u << 1, l, r, v);
else if (l > mid) modify(u << 1 | 1, l, r, v);
else {
modify(u << 1, l, r, v);
modify(u << 1 | 1, l, r, v);
}
pushup(u);
}
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i ++ ) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
alls.emplace_back(x1);
alls.emplace_back(x2);
event.push_back({y1, 1, x1, x2});
event.push_back({y2, -1, x1, x2});
}
sort(event.begin(), event.end());
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
m = alls.size() - 1;
build(1, 1, m);
int totlen = alls[m] - alls[0], pre = 0, ans = 0;
for (auto evt : event) {
int now = totlen;
if (tr[1].minv == 0) now = totlen - tr[1].cnt;
ans += (evt[0] - pre) * now;
pre = evt[0];
int x1 = find(evt[2]), x2 = find(evt[3]) - 1;
modify(1, x1, x2, evt[1]);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int _ = 1;
// cin >> _;
while (_ -- )
{
solve();
}
return 0;
}