【总结】主席树

这是一篇有关主席树的总结

主席树是什么?

对于原序列的每一个前缀[1···i]建立出一棵线段树维护值域上每个数出现的次数,则其树是可减的

PS:本篇随笔对于主席树的基本内容并没有深刻讲解,主要说明它的一些用法

其实就是很多一堆大量的权值线段树

(什么是权值线段树?就是每个节点维护不是位置,而是权值,比如 \([1,4]\) 维护的就是权值等于1到权值等于4的信息)

而且这些线段树还隐含了一个前缀和的功能

最简单的就是一个数列,长度为 \(n\) ,那么就建 \(n\) 棵权值线段树,第 \(i\) 棵权值线段树对应第 \(i\) 个数,存的是从第一个数到第 \(i\) 个数的信息(建第 \(i\) 棵权值线段树的时候,只要先把第 \(i-1\) 棵权值线段树复制一份,再把 \(i\) 位置上的信息加入中间就可以了)

那么我们如果要知道数列中 \(l\) 位置到 \(r\) 位置的数的信息,就只要把 \(r\) 上的权值线段树减去 \(l-1\) 的权值线段树,得到的线段树保存的就是 \(l\)\(r\) 的信息(其实就是一个差分)

然后我们发现每次都新建整个权值线段树又耗时间又爆内存,并且相邻两棵线段树之间改变的只有一点点内容,其它的都没有变,那对于这些不变的节点就不新建了,直接共用,即多棵权值线段树在某个位置共用一个节点

个人认为,主席树就是共用节点的权值线段树

主席树可以用来干嘛?

主席树的所有操作,基本上都可以说是对应一段区间,那么就都要先差分一下,以下所有功能都是差分之后的

  1. 查询区间Kth(第 \(k\) 大/小)

    主席树中记录的是 \(num\) ,即每个数字出现的次数,然后每次判断当前区间的左子树的 \(num\) 是否满足条件,再决定走左子树还是右子树(极其类似于Treap)

  2. 查询区间出现数字的和

    这只要把上面的 \(num\) 变成 \(val\) ,然后把差分后根节点的 \(val\) 输出就行了

  3. 查询区间中权值在 \([l,r]\) 之间的所有数字的和

    \(num\) 变成了 \(val\) 后,不直接返回根节点的值,而是返回主席树上 \([l,r]\) 区间的 \(val\) 值(因为主席树是权值线段树)

暂知的作用就这几个

几个小套路

  • 如果没有修改只有询问操作,那么可以直接静态主席树。但如果有修改操作,那么就要变成动态了。也就是说我们要有一个东西,可以维护能够修改的前缀和,那就BIT(树状数组)。所以动态主席树,一般就是树状数组套主席树的树套树

  • 如果不是一个数列,而是一棵树上要维护两个节点的信息,那么就把主席树的每个版本变成从父亲继承的就行了,最后的查询就树上差分

这些套路要在题目之中去理解

几道练习题

大体上从简到难(看个人理解)

七道题,后面的神题做得心累

没有数论题好做啊

从未结束

从此,主席树的学习告一段落

HNOI就要到了,可是HNOI最喜欢考的数据结构我还有很多没搞定

下一步——LCT

posted @ 2018-03-23 22:28  HYJ_cnyali  阅读(238)  评论(0编辑  收藏  举报