首页 > 其他分享 >扫描线 - 知识点梳理

扫描线 - 知识点梳理

时间:2023-07-12 17:25:23浏览次数:39  
标签:知识点 cur 覆盖 int 线段 节点 扫描线 梳理

扫描线算法可解决平面内平行坐标轴的线段有关的问题,例如求平面上平行于坐标轴的矩形的面积并,其原理在于模拟一条扫描线从下往上扫描。线段树是一种灵活的 Leafy Tree,可以灵活地扫描线上统计线段的分布情况,将一部分信息储存在分支节点上,另一部分信息下传至叶子节点,因此线段树是扫描线算法的核心。

算法实现

例题:Luogu P5490 【模板】扫描线
假设我们要求如图两个矩形的面积并。

我们无法直接求这样一个不规则图形的面积,于是对矩形按照平行于 \(x\) 轴的线段进行分层,就像下面这样:
现在我们将原图转化为了很多矩形。我们只需要用每个矩形的水平宽乘高就得到了矩形的面积。
问题转化为:如何求出每个矩形的水平宽?
水平宽由水平的线段堆叠形成:

很多不同位置的线段堆叠,求堆叠后的长度并,很容易想到离散化后,使用线段树维护。
这样我们可以模拟一条扫描线从底部往上扫描,每次经过一条线段就把它加入线段树中或将与它同一个矩形的线段从线段树中删除。
线段树上要记录当前段被覆盖的长度和被完全覆盖的次数。由于每个水平线段的信息对应着固定的线段树节点,而且未来有可能被清除,因此完全覆盖的标记既不需要也不能够下传,而要使用标记永久化。若当前段被完全覆盖,那么覆盖的长度就是段长,否则就是左子节点的覆盖长度和右子节点的覆盖长度之和。
上代码!

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1e5 + 5;
struct line {
	int l, r, y, w;
	bool operator < (line b) const {
		return y < b.y;
	}
}ln[2 * MAXN];
int n, m, a, b, c, d, xp[2 * MAXN], son[4 * MAXN][2], tag[4 * MAXN], root, cnt;
long long sum[4 * MAXN]; 
int build (int tl, int tr) {
	int cur = ++cnt;
	if (tl != tr) {
		int mid = (tl + tr) >> 1;
		son[cur][0] = build (tl, mid);
		son[cur][1] = build (mid + 1, tr);
	}
	return cur;
}
void pushup (int cur, int tl, int tr) {
	if (tag[cur]) sum[cur] = xp[tr + 1] - xp[tl];
	else sum[cur] = sum[son[cur][0]] + sum[son[cur][1]];
}
void modify (int cur, int tl, int tr, int ml, int mr, int x) {
	if (ml <= tl && tr <= mr) {
		tag[cur] += x;
		pushup (cur, tl, tr); 
	}
	else {
		int mid = (tl + tr) >> 1;
		if (ml <= mid) modify (son[cur][0], tl, mid, ml, mr, x);
		if (mr > mid) modify (son[cur][1], mid + 1, tr, ml, mr, x);
		pushup (cur, tl, tr);
	}
}
int main () {
	cin >> n;
	for (int i = 1;i <= n;i++) {
		cin >> a >> b >> c >> d;
		if (a > c) swap(a, c);
		if (b > d) swap(b, d);
		ln[2 * i - 1] = {a, c, b, 1};
		ln[2 * i] = {a, c, d, -1};
		xp[2 * i - 1] = a;
		xp[2 * i] = c;
	}
	sort (xp + 1, xp + 2 * n + 1);
	m = unique (xp + 1, xp + 2 * n + 1) - xp - 1;
	for (int i = 1;i <= 2 * n;i++) {
		ln[i].l = lower_bound (xp + 1, xp + m + 1, ln[i].l) - xp;
		ln[i].r = lower_bound (xp + 1, xp + m + 1, ln[i].r) - xp;
	}
	root = build (1, m - 1);
	sort (ln + 1, ln + 2 * n + 1);
	long long ans = 0;
	for (int i = 1;i < 2 * n;i++) {
		modify (root, 1, m - 1, ln[i].l, ln[i].r - 1, ln[i].w);
		ans += 1LL * (ln[i + 1].y - ln[i].y) * sum[root];
	}
	cout << ans << endl; 
	return 0;
}

易错点

主要是在实现线段树时,注意搞清楚什么标记该下传,什么标记不该。

拓展

扫描线的精髓在于使用线段树维护线段的长度,但其实线段树还可以干很多事,比如这道题:
例题:Luogu P8734 [蓝桥杯 2020 国 A] 奇偶覆盖
这道题将维护面积改为了分别维护奇覆盖和偶覆盖的面积。我们只需要在线段树上做修改:维护每个节点被完全覆盖的次数,奇数次覆盖的面积,和偶数次覆盖的面积。注意在 pushup 时,若该节点被完全覆盖过,我们需要优先将子结点中奇数覆盖的长度上传,若该节点被完全覆盖了偶数次,则子节点奇数覆盖的长度等于当前节点奇数覆盖的长度,反之则等于当前节点偶数节点覆盖的长度,然后当前节点的另一个长度只需要使用节点表示的段长减去已求得的长度即可求出。若没有被完全覆盖过,则直接将子节点的数据上传即可。
上代码! (gugu)
通过此题,我们发现扫描线的精髓在于线段树作为一个 Leafy Tree 维护线段信息的灵活性。

总结

扫描线这个算法能解决的问题是相对单一的,但扫描线能教给我们的其实主要是线段树作为 Leafy Tree 将一部分标记储存在结构节点而不下传的操作,以及通过离散化将直线上的点表示在线段树上并进行区间操作的方式。同时,扫描线本身也是一个基于时间戳的离线算法,其中包含了典型的从空间中抽象出时间轴的操作,它起到了在空间上将二维降为一维的效果。

例题

Luogu P8146 [JRKSJ R4] risrqnis
Luogu P1856 [IOI1998] [USACO5.5] 矩形周长Picture

标签:知识点,cur,覆盖,int,线段,节点,扫描线,梳理
From: https://www.cnblogs.com/mindeveloped/p/super-leech.html

相关文章

  • qml知识点概括一
    目录1.qml语言是什么?有什么优点?2.qml的语言的本质是什么3.qml文件文档结构以及界面布局元素4.qml常见的对象类型(1)Item(2)addImportPath设置qml模块路径(3)setContextProperty设置qobject对应的qml文档属性5.window下IDE的选择6pro文件的TEMPLE(1)QT工程pro文件模板变量(TEMPLA......
  • 答疑知识点
    1.re_path和path有什么区别1.表象上的区别pathpath里面支持固定,还有动态参数int,str,uuid,path re_pathre_path支持正则表达式2.源码上的区别 底层都是偏函数,对应的都是_path函数,本质上传递的Pattern不同,而day03源码里面分析,匹配时会找到外部resolver方法,再......
  • C++进制转换+扫描线算法(二维区间合并面积和)
    ......
  • Trie树 - 知识点梳理
    介绍Trie树,又名字典树,顾名思义就是为多个字符串的存贮与查找而生的,和现实中的字典差不多,其实就是一种字符查找自动机。通过对被查找串预处理,梳理为树形结构,在每次查找\(S\)时复杂度可以达到\(O(|S|)\)(而朴素查找复杂度为\(O(|S|+\sum_i|t_i|)\)),且占的空间比单独存贮字符......
  • jvm学习-垃圾回收的一些知识点
    部分图片和描述来自参考资料,非原创对象回收处理过程如何标定对象是否存活两种方法:引用计数方法可达性分析算法引用计数方法就和ReentrantLock可重入锁一样,内部维系着一个state,当同个线程重入结束后就会归零,但是这种方法有点问题publicstaticvoidte......
  • labview和西门子plc通信 知识点和领域范围:LabVIEW、西门子PLC、
    labview和西门子plc通信知识点和领域范围:LabVIEW、西门子PLC、通信LabVIEW是一种图形化编程环境,用于控制和测量系统的设计和开发。它提供了一个直观的界面,使工程师能够通过拖放和连接图标来创建程序。西门子PLC(可编程逻辑控制器)是一种常用的工业自动化设备,用于控制和监控生产过程......
  • 科目一知识点,自己写着玩~
    C1 可以开C2C3C4新政策说的C6 指的是轻型牵引挂车  年龄适用范围为:20~60周岁 且必须有小型汽车、小型自动挡汽车驾驶证一年以上资质。小型汽车的年龄要求:18周岁~~无上限。另外要说的一点是:70岁以上的人群考驾照要经过记忆力、判断力、反应力的测试,每年都要体检。而......
  • MySQL常用知识点总结
    MySQL常用知识点总结参考地址:(https://maifile.cn/est/a3206887806899/pdf)【一】知识点总结【二】多表查询【三】常用函数【四】Excel数据清洗......
  • Linux下路由配置梳理
    转自  散尽浮华  在日常运维作业中,经常会碰到路由表的操作。下面就linux运维中的路由操作做一梳理:------------------------------------------------------------------------------先说一些关于路由的基础知识:1)路由概念路由: 跨越从源主机到目标主机的一个互联网络来转......
  • 使用vue-super-flow的使用进行工作流的梳理
    1.安装依赖npminstallvue-super-flow2.在页面中引用<template><super-flow></super-flow></template><script>importSuperFlowfrom'vue-super-flow'import'vue-super-flow/lib/index.css'exportdefault{......