0%

线段树扫描线

简述

线段树扫描线算法准确的来说就是用线段树维护在一个二维空间中的一根和 $x$ 轴平行线上的信息($y$ 轴同理),通过把这跟扫描线从下向上扫一遍,就能得到二维平面上的一些信息。

而因为维护的是一个水平的直线,所以一般就是求矩形相关的信息了。

由于矩形有一个固定范围,因此我们一般将它分成上下边两个区间,一个加上操作,另一个消除操作。这样在中间算上这个矩形的贡献就可以了。下文称这些直线(区间)为关键直线,因为只有这里可能让线上的信息变化。

至于具体的维护什么信息就因题目而异了。

时间复杂度就是线段树的 $\log$ 加上离散化的二分 $log$,总的还是 $O(n\log n)$ 的。

最典型的例题就是矩形面积并了。


矩形面积并

Atlantis

题面上的数据很小,但用线段树做扫描线是 $O(n\log n)$ 复杂度的。

我们想用一条线从下向上扫一遍来求矩形面积并,我们考虑每条关键直线怎么更新答案。因为求的是面积,所以要考虑的是两条直线之间的答案。因为是求所有矩形的面积并,所以每次两条关键直线之间的面积一定是若干个宽是两条直线之间距离的矩形面积之和,就维护每一次的长有多少与宽相乘即可。由于坐标是实数,先离散化,然后用线段树维护直线上被覆盖的区间长度即可。这个将矩形下边记为 $+1$,下边记为 $-1.$

这里可以用到一个技巧:不把标记下放,因为每一个区间的加上后是会被整体减去的。因此是否被覆盖可以只考虑着一个点是否被整体覆盖,若没有则看两个儿子。另外,因为是区间长度,所以需要记录的不是点而是区间,所以把每个区间右边的区间信息弄在左端点上即可。

//注意实数啊,$lower_bound$ 找离散化也要开 $double..$

$code : $ https://paste.ubuntu.com/p/m4nyPVfvvK/


除此之外用于维护扫描线上的其他信息也是可以的,比如最大值。

最大 矩形权值交之和

窗口的星星

首先因为窗口大小是固定的,那么考虑一颗星星在窗口中的位置(如果被选中),那么他一定会在 $w\times h$ 的矩形内部,因此如果固定一颗星星在一个窗口的左下角,计算这个窗口内的所有部分的最大值(每个位置初始值是自己的值,其他星星的窗口交过来了就加上那颗星星的值)就是包含这个星星的最佳答案了。

那么我们就是要维护一个矩形内的交的部分的和,然后求最大值。

还是一样,考虑用一条扫描线,每一次拓展到一条矩形边的时候直接区间加它的权值,然后拓展完的时候求最大值。因为坐标还是很大所以还是要离散化。

注意,在以纵坐标排序的同时,需要保证一条线上先加再减,不然可能把答案给减没了。

$code:$ https://paste.ubuntu.com/p/6BxXC5T34B/

其他

这里列举一下出现的方法吧。

  • 矩形内点数和
  • 矩形面积交
  • 矩形外周长