(三)数据结构
线段树
普通线段树
我的线段树 (记录一下做题时犯的错误):
- 检查 函数是否调用。
- 区间操作 是否有可能大于 。
- 结构体中元素初值问题(是否赋初值,懒标记初值是否与题目操作冲突) 输出可能变得极大
- 动态开点线段树记得建第一个点(坑死我啦 什么都有可能
- 线段树空间记得开 倍(经典错误)
- 检查各个部分的手误
- 检查数据范围,数组是否开小
多刷了几道题,学习到了一些维护数据的方法。
例题 :区间方差 - 洛谷
这道题思路比较简单,就是将所求式子化简开来,转变成维护区间和与区间平方和即可。
由于模数不一定为质数,所以逆元并不一定存在,故不能直接计算。
基于操作建立线段树维护乘积,根节点保存答案。
离散化后,分讨 的存在性即可,需要考虑的情况有点小多。
例题 :[HEOI2016/TJOI2016]排序 - 洛谷
二分答案,考虑 函数的写法:
观察每次排序,它会把小于 的数放到一边,大于 的数放到另一边,于是上线段树区间修改。
考虑将小于等于 的数记为 ,大于 的数记为 ,
最后模拟完所有操作后,考察第 位是否为 即可。
二分的正确性分析:若当前理想解不成立,那么比它更小的解也不可能成立,二分正确。
例题 :小白逛公园 - 洛谷
区间最大子段和模板,维护区间 转移即可。
线段树优化建图
对于如一个点向区间连边的问题,由于边数过多,建图的复杂度直接爆炸,此时可以考虑线段树优化建图。
概述:
假设一个点 要向一个区间 连一条边权为 的边,这个区间必然可以用线段树表示成不超过 的小区间。
于是,将这个点向这些小区间的代表节点(虚拟节点)连边。那么就可以使所连的边数大大减少。
此外,从这些小区间到它们的子区间应连一条边权为 的边,可以这样想象,能连到这个区间,必然也能连到它的子区间中的点。
例题 :Legacy - 洛谷
对于这道题目,它既要求由点向区间连边,也要求区间向点连边。
考虑建立两棵线段树,分别维护入边和出边,第二棵线段树需要将父区间连向子区间的边反向。
对于操作 ,由线段树 的叶子结点向线段树 连边,操作 反之。
然后就是最短路模板了。
线段树的标记永久化
对于不支持懒标记下传的线段树而言,需要用到标记永久化的技巧。
标记永久化的前置条件:修改顺序不影响最后答案。
如果能正常 且满足上述条件,那么就可以进行标记永久化。
思路简述:
懒标记应该 时,按住不下放,在最后询问的时候考虑从根节点到询问区间的所有懒标记即可。
这样说可能不明晰,看个例子:
权值线段树
顾名思义,权值线段树是维护与值域相关信息的线段树。
举个例子,权值线段树的叶子维护有几个 ,它们的父亲节点维护有几个 和 。
可以武断地说,权值线段树维护的是值域上各个数的个数。
应用:权值线段树最广泛的应用就是解决整个数列的第 大(小)的数,具体方法如下(以求第 小数为例):
权值线段树的父亲节点维护数的个数和,在查询时:如果左子区间的数的个数大于 个,那么进入左子区间,否则进入右子区间。
思路比较简单,多配合其它知识一起考察,如线段树合并,可持久化线段树等。
例题:见例题 [HNOI2012]永无乡 - 洛谷。
线段树合并
前置知识:动态开点线段树
线段树合并常应用于树上问题,用于合并两棵线段树之间的信息。
前置条件:能够快速合并两个叶子结点。
合并过程:
合并分为两类:
-
合并叶子结点的信息(单点合并)
-
合并左右儿子的信息(区间合并)
如果当前两个节点有一个为空,(空节点合并后信息不改变)。
否则新建一个节点,保存合并后线段树的信息。
继续递归,直到叶子结点或有一个为空,回溯时返回新建节点编号。
容易发现,合并的复杂度为两棵线段树重合的节点个数。
技巧:设被合并的线段树为 和 ,如果被合并的线段树 的信息以后不会再用到,那么可以不用新建节点,而将信息直接合并到 的节点上。
例题 :[Vani有约会]雨天的尾巴 /【模板】线段树合并 - 洛谷
对于每个节点建立一棵线段树,配合树上差分修改,最后向上合并线段树即可。
裸的线段树合并。
一个套路:并查集维护连通性,每次操作就只用在并查集的代表元素之间。
这样对于每个点开一棵权值线段树,对于每个操作合并代表元素即可。
将每次修改分两段处理,查询时查询 的值即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】