扫描线口胡
前言
本片博客写于 lxl 学长回校讲课后不久,是笔者的一篇学习笔记,在此会详细介绍扫描线的有关内容,知识点和题大部分是 lxl 的课件上的。如有勘误,欢迎指出!
前置
对信息的理解
对于维护的信息我们可以把与信息相关的每一种限制都看成平面上的一个维度,维度越高也就说明信息限制越多,对应的就越不好维护。通常作为维度的有时间、序列下标、数值等。
在一个
我们查询信息,实际就是选择一个
为延续 lxl 优秀的画图习惯,这里补一张图,下面一次是一到四
自由度体系
这个体系一般用于描述静态问题,我们根据询问的参数数量定义问题的自由度数。注意这里自由度的度数与维数不一定对应。一般将动态问题离线转化为静态问题会增加一自由度,也就是时间维。
扫描线和差分
实质
扫描线是将高自由度问题转化为动态低自由度问题的方式,扫描线扫不同的维,扫不同的方向,会将原静态问题转换为不同形式的动态问题。
一维扫描线
对于一个静态的二维问题,我们可以用扫描线扫一维,数据结构维护另一维。在扫的过程中我们会在数据结构上进行一些修改查询,如果查询可以差分就直接差分,因为差分在不对答案造成任何影响的情况下能够降低问题难度,所以能差分就无条件差分即可。
我们还可以换一个角度看扫描线,我们可以从序列的角度看待问题。我们的扫描线扫到的位置实际就是修改查询区间的右端点,我们维护一个数据结构,它支持对于当前的右端点
关于扫描线扫一个多
差分方法
这里列举一点经典的差分方法:
- 对于序列上的区间
:差分为 的前缀。 - 对于树上的路径
:差分为 。 - 对于树上子树修改查询操作:用 dfs 序转化成区间问题。
- 对于树上子树修改、单点查询:可以转化成单点修改、前缀查询。
类似的转化还有很多,这些都需要我们有耐心步步转化,拆解问题。
差分的原因
根据 lxl 所讲,差分的问题就是“自由度”的问题。通过差分我们往往能将一个高自由度问题以极小代价转换为低维问题,而维数越低,信息越好处理。
也许有读者会问差分的常数,这一点不用担心。因为计算机做加减运算是比较快的,它真正慢的地方在于查询区间,你差分成前缀最多不到
对于 矩形的扫描线
在可差分的前提下,我们可先将其差分成两个
基础题
A
题面:
给一个长为
题解:
这个问题叫二位数点,是一个非常经典但基础的扫描线,我们把序列和值域当成信息的两维,对于每次查询我们都相当于在平面内选择一个矩形,数矩形内点数。然后就按照上面讲的
B
题面:
给一个二维平面,上面有
题解:
就是普通的扫面积、单点查。
过渡
接下来的内容与扫描线的运用有关,分为三种技巧,每种技巧笔者整理了一点经典的题。但不能保证题解写得很详细。
反演
这是一种正难则反的思想,对于正常查询操作不好做的题,我们可以考虑每个位置对答案的贡献。具体可以看后面的题。
给一个长为
要求:单
题解
我们首先可以考虑不同值对答案的贡献,因为不同的值贡献独立。但我们发现如果直接查区间外的和区间内的就会很麻烦,总之不好处理,于是就可以进行反演。
我们考虑每个位置对哪些询问有贡献,常见的处理方法是容斥一下,考虑每个位置对哪些询问没有贡献,这是相对好做的。于是我们考虑怎么样一个询问是满足条件的。
所以对于每个值
所以现在考虑将区间的左右端点拿去建立平面直角坐标系,然后将满足条件的矩形加进去。因为矩形个数是
平面上有一些点,点有点权。给你固定长宽的矩形,求能覆盖的最大权值和。
数据范围:
题解
考虑如果扫描线去扫一维,那么第二维似乎无法处理,因为我们需要找到一段最值区间,这个不好维护。于是考虑每个点对矩形的一个顶点在那些位置有贡献,最后我们其实只需要找到全局最值点即可。
给
要求:单
题解
因为区间可能包含若干点,不好统计,所以考虑容斥。我们还是用反演的思路,我们去找相邻两点之间的矩形个数。所以就把初始矩形抽象成一个点,查询就是查线性个区间。
区间子区间
这种题一般是查询一个区间内所有子区间的信息,一般的方法是把一个单独的区间看成平面上的点,查询的区间就是一个上三角。对于这种图形有不同的处理方式,因为平面右下半边贡献为零,所以可以把上三角补成矩形,且通常是
可以扫描线扫一维。于是我们需要做的就是区间维护、查询区间历史和。那么现在考虑如何用线段树维护历史和?
历史和线段树
我们需要维护两个序列
有了特殊的标记后我们就要思考如何合并并且下放标记?比如现在依次有修改操作
现在当成有历史合并
一点题
放一个板子-->this
当然这个题可以用 st 表薄纱区间和线段树。
给定一个
题解
考虑如何刻画充要条件?对于一个区间
对于一个等式我们先移项变成
具体的,对于
补:其实对于最后的解决方式还可以用单调栈啊,也许码量还会减少。
实际写代码的时候会发现对于一操作(根据写法不同也可能是二操作)我们不好维护,这时候其实可以在初始化里面解决,具体怎么办可以自行思考。(这是提升代码能力的好机会)
升级一下上一道题。现在还有区间查询。
题解
其实就是套上一个历史和线段树就做完了。
稍微改一下前面的题。现在要求
数据范围:
题解
lxl 瑞平:糖体。
的确如此,因为
唉都2025了啊!
题目给了两个序列和若干询问,每次询问一个区间
题解
考虑这还是板子的加强版呐!但是一道很典的题。可以套路地想到历史和线段树,现在考虑维护哪些信息?
首先我们会维护区间长、历史和、还有答案。因为我们可以将最大值通过单调栈变成区间加,所以只用考虑加矩形的时候会发生什么变化?我们考虑以下形式:
这个形式可拆成:
于是我们就可以维护
TEST_90(个人觉得比较有意思的题)
求区间子区间满足内部出现颜色数为奇数的个数。
题解
容易想到用异或操作来翻译此题。现在只用考虑如何维护标记。对于依次有形如若干异或标记、若干历史和标记、若干异或标记、若干历史和标记的东西,我们其实可以把一段异或化简成一次异或操作。如果两段历史和中间没有标记了就不管它。现在我们稍微分析一下中间有一个异或标记的情况。
假设前面有
换维扫描线
顾名思义,就是如果维护一维后剩下一维不好处理就可以考虑换维。常见的比如时间-序列平面中我们通常都是扫时间,但是如果遇到有的神秘题目不好做的时候,我们可以尝试扫序列维护时间。反正就是哪一位好差分就扫哪一位。
然后就看一点题目找感觉吧(
支持区间加、查询点单值小于某数的时间。
题解
第一种操作相当于一个
因为笔者个人原因,不想写题所以这部分的内容就咕了。主要是这种题跟普通扫描线区分度不高,可能是一种个人习惯,有时又需要一点意识。
一点杂题
查询静态区间中长度为一到十的极长值域连续段个数。
题解
可以考虑扫描线。若我们扫区间右端点,那么我们需要维护每一个左端点的答案。首先思考现在新加入一个数
假设
首先解释为什么需要拿出值域在
然后就是考虑从右往左更新答案。如果枚举到的值
代码很短就不放了。
给一棵有根树和排列
题解
对于这种区间子区间题,我们需要对平面维护若干矩形修改和矩形查询。现在可以先考虑什么样的
首先我们要思考我们要统计什么?我们可以对于每一个三元组
现在思考对于一个二元组
令
然后另外两种情况可以见下图。
现在唯一的问题是矩形数量太多,我们需要扔掉一些被完全覆盖的区间,这个问题用树上启发式合并枚举就可以解决。具体的,固定一个
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律