😊 | Powered By HeartFireY |
文章目录
- 一、 主席树维护区间第K大
- 二、主席树维护线段树区间修改(标记永久化)
- 三、求区间内不同的数字个数/求区间大于的数字有多少
- 四、求区间小于等于的数字个数(二分查询)
- 五、求区间Mex
- 六、求区间内出现次数大于>=k次的最前数
- 七、主席树+树上路径
一、 主席树维护区间第K大
📕 | Require:主席树 |
主席树最基础的应用,对于给定的序列建立权值数组,对于每个元素建立一棵主席树,维护的数字个数(前缀和)。查询时在树上二分查找。对于当前节点判断左子树的节点个数是否满足比大,如果满足则向左递归查询,否则减去左子树节点个数向右子树递归查询。
二、主席树维护线段树区间修改(标记永久化)
📕 | Require:可持久化线段树、主席树 |
主席树可以维护线段树的区间修改,但是要求线段树动态开点。
在区间更新的时候,对每个点打永久化标记,对于跨越区间的点需要直接修改。查询时找到对应的完全覆盖区间加上这个区间的标记*(区间长度)
三、求区间内不同的数字个数/求区间大于的数字有多少
📕 | Require:思维变换、主席树 |
求区间内不同数字个数的问题可以转化为求区间内小于等于的数字个数:
对于每个数字记录下一个最近的相同数字下标,那么查询区间内不同数字的个数实际上就是在查询区间内的个数(下一个相同的数字位于区间之外)。那么现在不难发现对于给定区间,如果,那么表示与相同数字点位于区间之外。那么求不同数字个数问题便转化为给定求所有满足的个数。
那么我们只需要处理出数组,然后用主席树对每个节点维护权值数组,然后区间查询数目即可。
四、求区间小于等于的数字个数(二分查询)
📕 | Require:二分查找、主席树 |
建立权值数组,对每个节点维护一颗主席树。查询为单点查询,查询数字对应的权值数组的个数。然后对于每个询问,我们在区间内二分枚举所有可能的数字,然后查询区间第小。反复查询求得一个满足的最大。那么这个就是我们想要得到的答案。
五、求区间Mex
📕 | Require:思维、主席树 |
给定长度的数组,,以及次询问,每次给出一个数对表示区间起点终点,要求对于给定的询问,回答在该区间内最小未出现的数字。
建立权值数组,对于每个点建立一棵主席树,维护权值最后一次出现的位置,那么对于查询就是查找第棵树上出现位置小于的权值,那么只需要维护最后一次出现位置的最小值即可。
主席树解决该问题属于在线算法。这种题目可以用莫队强制离线处理。
六、求区间内出现次数大于>=k次的最前数
📕 | Require:思维、主席树 |
对于给定的序列,输出待查询区间内出现次数严格大于区间长度一半的数字。
**思路:**考虑对查询过程进行剪枝,排除非法子树,向合法子树搜索。
首先考虑非法状态:因为对于主席树上任意一个节点,其代表的意义是管辖区间内数字的个数。因此对于主席树上某个节点,如果其代表区间数字的数目比区间长度的一半(也就是)要小,那么子区间不回再出现满足该条件的数,在这种情况下可以直接返回。
剩下的部分就是查询的板子。非法状态实际上就是在对查询过程进行剪枝。
七、主席树+树上路径
📕 | Require:树剖、LCA、主席树 |
给定一棵 个节点的树,每个点有一个权值。有 个询问,每次给你 你需要回答 和 这两个节点间第
动态查询树上区间点权第小,且查询之间具有关系,因此考虑建立主席树维护区间信息。
首先回顾主席树维护线性区间第大/小时我们的处理思路:
对于全局区间第小时,我们建立全局权值线段树,维护的区间和表示某点子树中点的个数。那么我们在寻找区间第小时,只需要左右二分寻找即可。而对于某个区间的第小,一个朴素的方式便是我们每次都建立一颗线段树,但显然这样是不明智的算法。那么我们是如何查询这个区间第小的呢?
对于这个维护的过程我们很容易联想到前缀和的概念,我们可以先离线建树,对于每个点建立一棵主席树,维护区间,那么对于区间查询时,我们只需要查询到区间和即可取得区间的信息,实现区间查询。
然后分析样例,作出样例所示的树(假设以为根节点):
那么我们可以发现,对于树上区间查询,我们也可以利用类似于线性区间查询的思路进行解决,但是由于树的结构限制,我们把线性区间的前缀和改为树上前缀和的形式:
下面我们来说明这个式子:
如上,从根节点到号节点的路径+从根节点到号节点的路径重复了两次,那么我们要减去重叠的信息:对于根节点到交点父节点的信息均重复两次,到交点的信息重复一次(因为交点在链上,需要保留一次信息),因此前缀和形式便是。