扫描线学习笔记

扫描线是一种算法思想,其特征为将静态 \(k\) 维问题转化为动态 \(k - 1\) 维问题。动态 \(k - 1\) 维问题往往需要数据结构维护。

例题

【模板】扫描线

题意:求矩形面积并,其中每个举行的四边平行于坐标轴。

考虑扫描线,将静态 \(2\) 维问题转化为动态 \(1\) 维问题。

具体的,考虑按 \(y\) 轴排序每根与 \(x\) 轴平行的线段。随后逐个枚举并使用线段树维护。这里不特别讲线段树维护,可以理解为需要一个区间加查区间非零个数(保证全局查询)的线段树,可以自行去看题解。

代码:

#include <iostream>
#include <algorithm>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
using namespace std;
struct segment {
	int y, x1, x2, mk;
	segment(int y = 0, int x1 = 0, int x2 = 0, int mk = 0): y(y), x1(x1), x2(x2)\
	, mk(mk) {}
	bool operator<(segment o) {
		return y < o.y;
	}
}sg[2000010];
int x[2000010], x1, y1, x2, y2, n, cnt, ans;
struct d {
	int l, r, tot, len;
	d(int l = 0, int r = 0, int tot = 0, int len = 0):l(l), r(r), tot(tot)\
	, len(len) {}
}dat[8000010];
void pushUp(int p) {
	if (dat[p].tot > 0) {
		dat[p].len = x[dat[p].r + 1] - x[dat[p].l];
	} else {
		dat[p].len = dat[2 * p].len + dat[2 * p + 1].len;
	}
}
void build(int p, int l, int r) {
	if (l == r) {
		dat[p] = d(l, r, 0, 0);
	} else {
		dat[p] = d(l, r, 0, 0);
		int mid = (l + r) / 2;
		build(2 * p, l, mid);
		build(2 * p + 1, mid + 1, r);
	}
}
void modify(int p, int cl, int cr, int v) {
	int l = dat[p].l, r = dat[p].r;
	// cout << p << " " << l << " " << r << "\n";
	if (x[r + 1] <= cl || x[l] >= cr) {
		return;
	}
	if (x[l] >= cl && x[r + 1] <= cr) {
		dat[p].tot += v;
		pushUp(p);
		return;
	}
	modify(2 * p, cl, cr, v);
	modify(2 * p + 1, cl, cr, v);
	pushUp(p);
}
signed main() {
	cin >> n;
	rep (i, 1, n) {
		cin >> x1 >> y1 >> x2 >> y2;
		sg[2 * i - 1] = segment(y1, x1, x2, 1);
		sg[2 * i] = segment(y2, x1, x2, -1);
		x[2 * i - 1] = x1;
		x[2 * i] = x2;
	}
	n *= 2;
	sort(sg + 1, sg + n + 1);
	sort(x + 1, x + n + 1);
	cnt = unique(x + 1, x + n + 1) - x - 1;
	build(1, 1, cnt - 1);
	rep (i, 1, n - 1) {
		modify(1, sg[i].x1, sg[i].x2, sg[i].mk);
		rep (j, 1, 3) {
			// cout << dat[j].l << " " << dat[j].r << " " << dat[j].tot << " " << dat[j].len << "\n";
		}
		// cout << dat[1].len << "\n";
		ans += dat[1].len * (sg[i + 1].y - sg[i].y);
	}
	cout << ans << "\n";
}
posted @ 2024-07-29 21:57  IANYEYZ  阅读(11)  评论(1编辑  收藏  举报