扫描线
扫描线
引入
扫描线一般运用在图形上面,它和它的字面意思十分相似,就是在一整个图上面扫来扫去。最经典的还是二维矩形面积并问题。
二维矩形面积并
在二维平面上给出若干个矩形,求所有矩形构成的图形的并。
过程
先放一张不要钱捡来的图片。
懂了吧?是不是很简单?
相信你已经懂了。
其实这张图在这里,这篇学习笔记就已经写完了。
具体的
我们可以搞一个线段树,然后维护一下这个东西,然后这么搞一下,就可以了。
参考代码
参考自 UKE_Automation 的博客。
代码不难理解,线段树需要注意的每一个节点对应的是线段上的端点,所以写法略不同于序列(具体的,线段树维护的区间右端点要加一)。另外,由于题目数据范围是 1e9 级别,所以要离散化。注释懒得写了,参考原文。
// P5490 【模板】扫描线 & 矩形面积并
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x;
}
const int N = 4e5 + 10;
int n;
struct seg {
int l, r, h, t;
bool operator < (const seg & cmp) const {
return h != cmp.h ? h < cmp.h : t > cmp.t;
}
} a[N];
int b[N];
struct node {
int l, r, s, len, lazy;
} tree[4 * N];
#define lc p << 1
#define rc p << 1 | 1
void pushup(int p) {
if (tree[p].s) {
tree[p].len = b[tree[p].r + 1] - b[tree[p].l];
} else {
tree[p].len = tree[lc].len + tree[rc].len;
}
}
void build(int p, int l, int r) {
tree[p].l = l, tree[p].r = r;
if (l == r) return;
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
}
void update(int p, int l, int r, int v) {
if (tree[p].r + 1 <= l || r <= tree[p].l) return;
if (l <= tree[p].l && tree[p].r + 1 <= r) {
tree[p].s += v;
pushup(p);
return;
}
update(lc, l, r, v);
update(rc, l, r, v);
pushup(p);
}
signed main() {
n = read();
for (int i = 1; i <= n; i++) {
int A = read(), B = read(), C = read(), D = read();
b[2 * i - 1] = A;
b[2 * i] = C;
a[2 * i - 1] = {A, C, B, 1};
a[2 * i] = {A, C, D, -1};
}
n *= 2;
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + n);
int ll = unique(b + 1, b + 1 + n) - b - 1;
for (int i = 1; i <= n; i++) {
a[i].l = lower_bound(b + 1, b + 1 + ll, a[i].l) - b;
a[i].r = lower_bound(b + 1, b + 1 + ll, a[i].r) - b;
}
build(1, 1, ll - 1);
int ans = 0;
for (int i = 1; i <= n; i++) {
update(1, a[i].l, a[i].r, a[i].t);
ans += (a[i + 1].h - a[i].h) * tree[1].len;
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号