问题
主席树、可持久化线段树、动态开点线段树指向的都是同一类问题。即给定一个序列,求与等级、名次相关的答案,常用线段树计数加减的方式解决,在需要的时候也可以对等级、名次对应的数值离散化,前提是没有修改或允许离线操作
算法原理
为了解决此类问题,需要对每个序列节点建一棵以询问目标大小为值域的线段树,每一棵线段树都有一个它对应的前驱线段树,并成为此前驱的扩展和延伸。
例如(poj2104 kth number),对于求解区间第k大(小)问题,对给定的整个序列的每个点建权值线段树,树的值域可以是离散化或非离散化后的点的数值的值域,线段树维护一个size域,即在序列1~i中出现的在数值区间[l,r]中的数的个数,因此每个任意点i的线段树的前驱线段树就是点i-1的线段树,因此每棵线段树可以看作一个前缀和的处理。若要处理序列区间[a,b]的区间第k大(小),把线段树(b)和线段树(a-1)的权值和相减就可以得出序列区间的权值和了。
例如(bzoj2588 count on a tree),对于求解树上第k大(小)问题,可以解构整棵树,用倍增或树链剖分或dfs序处理整棵树(甚至是森林),那么,我们就要对每个节点建权值线段树,此时的前缀和就是根节点到该子节点的权值前缀和了。要注意,这里求解节点u到v的权值第k大,即求解线段树(u)+线段树(v)-线段树(lca(u,v))-线段树(fa(lca(u,v)))。
时间复杂度大概都是O(n * log2 (len))的,空间复杂度理论上也是O(n * log2 (len)),但是如果是用静态存储池来开点一般要开两倍的空间,动态的话就不说了,那很容易re。
算法应用
此类数据结构可以解决名次类的静态乃至动态的区间型问题,如第k大、中位数乃至树上的问题