初始主席树
•参考资料
[1]:树状结构之主席树
[2]:主席树入门详解+题目推荐
[3]:主席树 by 孤独·粲泽
[4]:主席树(入门篇)
•抛出问题
给定 n 个数,m 次操作,操作类型有:
(1)在某个历史版本下的单点修改;
(2)输出某个历史版本下某个位置的值的值;
其中 $n,m\leq 10^6$;
•问题的解
这类问题,一般可以通过主席树解决;
因为每次操作只改变单点的值,那么形成的新版本较当前的版本而言,只是改变了某条链;
而线段树中,最长的链的节点个数不超过 $log_{2} n+1$,所以只需改变这 $log_{2} n+1$ 个节点的信息即可;
而其他节点均可重用之前版本的节点信息;
•相关题目
上述问题可以参考这道题目:洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)
题目解析的话,参考这篇博文:P3919 【模板】可持久化数组 -初步探究主席树
在博主巨巨的影响下,我的代码风格顺利同步过去;
•Code
•另一类问题
给你 n 个数,m 次询问,每次询问 [l,r] 区间第 k 小的值;
•问题的解
这或许是主席树的经典题目吧;
建立 n+1 个线段树,每个线段树维护一个前缀和,并用 rt[] 记录第 i 个线段树的根节点;
询问的时候,只需要将 rt[ r ] 与 rt[ l-1 ] 做差即可;
•相关题目
与此相关的一道题目为:HDU2665 Kth number
题干要求是求第 k 大,但实际求的是第 k 小,按照求第 k 小的思路求解即可;
推荐博客:树状结构之主席树
•Code
•进阶题目(HDU4417 "Super Mario")
给你 n 个数,m 次询问,每次询问 [l,r] 中有多少数小于等于 k;
•题解
和上一个求区间第 k 小的题目相仿,只不过在查找的时候不同;
定义 $query(l,r,pos,k)$ : 以 pos 为根节点的线段树中,小于等于 k 的总个数;
$ans = query(0,siz,rt[r],k) - query(0,siz,rt[l-1],k)$;
因为存在 k 小于任意一个数的情况,所以建树的时候从 0 开始,即 $build(0,siz,1)$;
siz : 将 n 个数去重后的数的个数;
•Code
•踩坑
1.b数组去重后的大小为 siz,不管是建树,还是更新或查询,最大范围为 siz 而不是 n;
2.查找 k 所处的位置是用 $upper_bound()-(b+1)$,因为 b 中可能不包含 k;