扫描线
引入
先来看一道题:油漆面积。
给出若干个矩形,求这些矩形的面积并。
这题数据范围很小,用一个二维差分就行了。
那把范围调大呢?(即模板扫描线)
这个时候就需要使用线段树来维护扫描线了。
思想
想象一下,在平面直角坐标系上面有很多个矩形,有一条线从底部开始往顶部进行扫描,每次统计在 y 坐标的一个区间内且每行被至少一个矩形覆盖的部分完全相同的部分对于答案的贡献。
这个要怎么维护呢?尝试把矩形变成两条线段去做贡献,当扫描线扫到一个矩形的下底时,会使得这个矩形对应的 x 坐标区间内每个元素都加一,同理扫到上底的时候每个元素都要减一。这就变成了区间修改。
那么算贡献呢?只要知道有多少元素为正数,用线段树去维护即可。
由于模板数据范围较大,需要离散化,注意处理边界的细节。
Code
用的永久化标记的写法。
点击查看代码
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 2e5 + 10; struct Edge { int h, x, y, z; } e[N]; struct SegTree { int l, r, cov, len; } tr[N * 8]; int n, dce[N], dce_[N], dcnt, ally[N]; ll ans; void pushup (int id) { // tr[id].cov = min(tr[id * 2].cov, tr[id * 2 + 1].cov); if (tr[id].cov) tr[id].len = tr[id].r - tr[id].l; else tr[id].len = tr[id * 2].len + tr[id * 2 + 1].len; } void build (int id, int l, int r) { tr[id] = {dce_[l], dce_[r + 1]}; if (l == r) return ; int mid = (l + r) >> 1; build(id * 2, l, mid), build(id * 2 + 1, mid + 1, r); } void modify (int id, int l, int r, int x, int y, int z) { if (x <= tr[id].l && tr[id].r <= y) { tr[id].cov += z, pushup(id); return ; } if (y < tr[id].l || tr[id].r < x) return ; int mid = (l + r) >> 1; modify(id * 2, l, mid, x, y, z), modify(id * 2 + 1, mid + 1, r, x, y, z); pushup(id); } int main () { ios::sync_with_stdio(0), cin.tie(0); cin >> n; for (int i = 1, x1, y1, x2, y2; i <= n; i++) { cin >> x1 >> y1 >> x2 >> y2, dce[i * 2 - 1] = x1, dce[i * 2] = x2; e[i * 2 - 1] = {y1, x1, x2, 1}, e[i * 2] = {y2, x1, x2, -1}; ally[i * 2 - 1] = y1, ally[i * 2] = y2; } n *= 2, sort(dce + 1, dce + n + 1), sort(e + 1, e + n + 1, [](const Edge &i, const Edge &j){return i.h < j.h;}), sort(ally + 1, ally + n + 1), dce[0] = -1; for (int i = 1; i <= n; i++) if (dce[i] != dce[i - 1]) dce_[++dcnt] = dce[i]; build(1, 1, dcnt - 1); for (int i = 1, j = 1; i < n; i++) { for (; j <= n && e[j].h == ally[i]; j++) modify(1, 1, dcnt - 1, e[j].x, e[j].y, e[j].z); ans += 1ll * (ally[i + 1] - ally[i]) * tr[1].len; } cout << ans; return 0; }
本文作者:wnsyou の blog
本文链接:https://www.cnblogs.com/wnsyou-blog/p/18302418/scanning
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步