主席树(可持久化线段树)
问题描述:
给定N个数(int范围内),一共M次询问,每次都要询问区间[[l,r]的第k大的数。 其中N, M, l, r均不超过$2\times10^5$,保证询问有答案
主席树本名可持久化线段树,也就是说,主席树是基于线段树发展而来的一种数据结构。其前缀”可持久化”意在给线段树增加一些历史点来维护历史数据,使得我们能在较短时间内查询历史数据,图示如下。
当每插入一个数据时,会修改$logn$个节点,因为主席树的左右子树节点编号不能够计算得到,而是需要记录下来。
1 | static constexpr int N = 200010 |
将数组复制一份,进行排序,去掉重复的数字离散化。
以离散化后的数组为基础建立一个全零的线段树,称为基础主席树
对原数据中每一个[1,i]区间统计,有序地插入新节点,i每增加1,就会多一个数,仅需对主席树对应的节点增加1即可
对于查询[l, r]中第k小值的操作,找到[l, r]对应的根节点,按照线段树操作的方法即可
建立基础主席树
1 | void build(int &u, int l, int r) { |
向主席树中加入元素
1 | int modify(int pre, int l, int r, int x) { |
查询区间第k大,注意区间下标是从1开始
1 | int query(int u, int v, int l, int r, int k) { |