扫描线 笔记(面积并问题)

本文介绍了如何使用扫描线算法解决多个矩形的面积并问题。通过将垂直于x轴的直线从左向右扫描,依次计算扫过的矩形面积,结合线段树数据结构进行区间操作,实现矩形边的离散化和覆盖状态的维护。文章详细讨论了算法实现过程,包括线段树的构建、区间更新和避免越界的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P5490 【模板】扫描线

扫描线主要解决的是几个矩形的面积并问题.

当然也可以用来解决周长并问题 , 不过由于暂时不会就不说了.

比如下面的几个矩形:

我们假设有一条垂直于 x x x 轴的直线从左往右扫描, 下图将它标记为红色. 不难想到可以计算这条直线扫过的面积来得到所有矩形的面积并.

显然这条直线会碰到最左边的垂直于 x x x 轴的边.

把从最左边的垂直于 x x x 轴的边开始到第二条垂直于 x x x 轴的边中间扫过的矩形的面积标记下来.

此时扫过的矩形的面积就是第一条垂直于 x x x 轴的边长度乘上从最左边的垂直于 x x x 轴的边开始到第二条垂直于 x x x 轴的边扫过的距离.

以此类推, 这是扫到第 3 3 3 条垂直于 x x x 轴的边.

新扫过的面积即橙色面积就是前两个垂直于 x x x 轴的边的长度和乘新扫过的距离.

而扫到第三条垂直于 x x x 轴的边的时候我们发现前三条垂直于 x x x 轴的边的纵坐标有重复部分. 这是怎么计算呢?

可以把覆盖的区间标记一遍, 最后看总长度.

扫到黄色区间结束的时候, 我们发现有一条边不用再继续往下算了(就是最下面那条), 然后我们把它删去即可.

其实我们可以在插入一条边的时候把这个边里的点对应的纵坐标加一, 删除的时候减一, 然后可以达到这种效果.

然后我们发现, 我们要一个可以支持区间操作的数据结构, 可以用线段树来维护这条扫描线.

附上扫描结束的几张图:

然后看怎么实现:

首先要知道存什么: 我们想知道的是每一个矩形两条垂直于 x x x 轴的边. 还要标记一下这是左边那条还是右边那条.

那其实只要保存一条边的上端点和下端点的纵坐标及横坐标外加一个标记就够了.

注意有 n n n 个矩形, 就要存 2 n 2n 2n 条边.

int n, lcnt;

//...

struct node1{
   
	long long x, highy, lowy, flag;
}l[200005];

node1 make_node1(long long xx, long long hy, long long ly, long long f){
   //构造函数
	node1 T;
	T.x = xx;
	T.highy = hy;
	T.lowy = ly;
	T.flag = f;
	return T;
}

//...

for(int i = 1; i <= n; ++i){
   
	int x_1, x_2, y_1, y_2;
	scanf("%d%d%d%d" ,&x_1 ,&y_1 ,&x_2 ,&y_2);
	l[++lcnt] = make_node1(x_1, y_2, y_1, 1);
	l[++lcnt] = make_node1(x_2, y_2, y_1, -1);
}

别忘了把这些边按 x x x 排序.

但是我们看数据范围:

对于 % 100 \% 100 %100 的数据, 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105 0 ≤ x 1 ≤ x 2 ≤ 1 0 9 0 \le x_1 \le x_2 \le 10^9 0x1x2109 0 ≤ y 1 ≤ y 2 ≤ 1 0 9 0 \le y_1 \le y_2 \le 10^9 0y1y2109

很明显我们如果区间更新的话, 扫描线就要在 [ 0 , 1 0 9 ] [0, 10^9] [0,10

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值