数据结构:线段树
线段树是算法竞赛中常用的用来维护 区间信息 的数据结构。
线段树可以在
树状数组是一种支持 单点修改 和 区间查询 的,代码量小的数据结构。
什么是「单点修改」和「区间查询」?
假设有这样一道题:
已知一个数列
,你需要进行下面两种操作:
- 给定
,将 自增 。 - 给定
,求解 的和。 其中第一种操作就是「单点修改」,第二种操作就是「区间查询」。
类似地,还有:「区间修改」、「单点查询」。它们分别的一个例子如下:
- 区间修改:给定
,将 中的每个数都分别自增 ; - 单点查询:给定
,求解 的值。 注意到,区间问题一般严格强于单点问题,因为对单点的操作相当于对一个长度为
的区间操作。
普通树状数组维护的信息及运算要满足 结合律 且 可差分,如加法(和)、乘法(积)、异或等。
需要注意的是:
事实上,树状数组能解决的问题是线段树能解决的问题的子集:树状数组能做的,线段树一定能做;线段树能做的,树状数组不一定可以。然而,树状数组的代码要远比线段树短,时间效率常数也更小,因此仍有学习价值。
有时,在差分数组和辅助数组的帮助下,树状数组还可解决更强的 区间加单点值 和 区间加区间和 问题。
ST 表(Sparse Table,稀疏表)是用于解决 可重复贡献问题 的数据结构。
什么是可重复贡献问题?
可重复贡献问题 是指对于运算
,满足 ,则对应的区间询问就是一个可重复贡献问题。例如,最大值有 ,gcd 有 ,所以 RMQ 和区间 GCD 就是一个可重复贡献问题。像区间和就不具有这个性质,如果求区间和的时候采用的预处理区间重叠了,则会导致重叠部分被计算两次,这是我们所不愿意看到的。另外, 还必须满足结合律才能使用 ST 表求解。
什么是 RMQ?
RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。解决 RMQ 问题有很多种方法
在学习单调队列前,让我们先来看一道例题。
本题大意是给出一个长度为
的数组,编程输出每 个连续的数中的最大值和最小值。
最暴力的想法很简单,对于每一段
很显然,这其中进行了大量重复工作,除了开头
这时所用到的就是单调队列了。
给你一个长度为 n 的序列
Sqrt Tree 可以在
可以参考 ouuan 的博客/莫队、带修莫队、树上莫队详解/树上莫队。
树上莫队同样可以参考文章。
树分块除了应用于莫队,还可以灵活地运用到某些树上问题中。但可以用树分块解决的题目往往都有更优秀的做法,所以相关的题目较少。
顺带提一句,「gty 的妹子树」的树分块做法可以被菊花图卡掉。
先进行树分块,然后对每个块的关键点,预处理出它到祖先中每个关键点的路径上颜色的 bitset,以及每个关键点的最近关键点祖先,复杂度是 bitset
存下来的复杂度。
回答询问的时候,先从路径的端点暴力跳到所在块的关键点,再从所在块的关键点一块一块地向上跳,直到 bitset
已经预处理了,剩下的在暴力跳的过程中计算。单次询问复杂度是 bitset
的 count()
,求 bitset
的 _Find_first()
。
所以,总复杂度为
1 | #include <algorithm> |
这题和上一题基本一样,唯一的区别是得到 bitset
后如何计算答案。
由于 BZOJ 是计算所有测试点总时限,不好卡,所以可以用 _Find_next()
水过去。
正解是每 bitset
,因为标准库的 bitset
不能取某
代码可以参考 这篇博客。(绝对不是本人不想写了)
前置问题
前置问题:
XOR AX, AX
而不是用MOV AX, 0H
,为什么?TEST
指令通常在什么情况下使用?