算法与数据结构 4 - 主席树(可持久化权值线段树)

0. 主席树的名字

主席树和主席没有关系。

它之所以叫主席树,是因为它的发明者叫 HJT ,和时任这一职务的那个人一样。

1. 例题

静态查询数组 a[l,r]k 大的值。

一种暴力的方法是:每次询问对区间进行排序。这样的时间复杂度是 O(mnlogn),妥妥地超时。

2. 二分的应用

先来考虑:假如已经知道值域 W=[1,m] 内每个数在 a[l...r] 的出现次数,那么可以判断 x[1,1+m2]xa[l...r] 里出现了多少次。

如果出现次数 >k,则说明区间第 k 大的数 p[1,1+m2],然后就可以继续二分;如果出现次数 <k,则说明区间第 k 大的数 p[1+m2+1,m],然后也可以继续二分。

然后,为了求出 a[l...r] 中数值在 [p,q] 的数有多少个,需要引入权值线段树和可持久化数据结构。

3. 权值线段树和可持久化数据结构

在权值线段树中,若节点 s 维护区间 [l,r],则它的值表示在整个原数组中,数值在 [l,r] 中数字的个数。这样,就实现了求数值在 [p,q] 的数有多少个。

对于限定的 a[l...r],可以按顺序将 ai 插入到权值线段树里。每插入一个数字 ai 记录一下这棵线段树 sgti。接下来,用 sgtrsgtl1 即可得到区间 [l,r] 的权值线段树。

为了解决空间不够的问题,需要对插入操作进行一些改进。可以发现线段树的单点修改最多改变 logm 个节点的值。那么可以在每次修改时新开一个节点,而不是修改原来的节点。接下来,将新节点的左右儿子指针指向原节点的左右儿子;如果儿子也需要修改,则新开一个儿子节点,然后继续上述操作。这样,只需要找到每个历史版本的根节点,就可以遍历这个版本的线段树。

4. 总结

主席树是一种可持久化数据结构,通过查询两个历史版本实现了类似于前缀和的效果,实现了求出 a[l...r] 的权值线段树,进而得到区间第 k 大的值。

posted @   cwkapn  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示