权值线段树与Kth
0.前言
你打开了一道题:
一个长为
n 的序列A ,进行n 次单点修改或查询第k小数字的操作。
经典的全局第k小问题,平衡树、树状数组、线段树都可以轻松维护。
题目要求强制在线,且
n\leq 10^6 。
树状数组只能离线,而平衡树常数巨大。于是你只能望向线段树 ....
1.权值线段树
线段树,它是一个维护区间强有力的工具。权值线段树是一个普通线段树的应用,相当于是开了一个桶,每一个叶子节点装的信息是权值等于该点的个数。对于每一个节点内装的都是该范围有多少个数,底层原理就是线段树的单点修改和区间查询了。考虑到线段树的结构就是二分区间,我们每次查找kth的时候其实就是查找第一个前缀和大于等于k的数字。
比如下面这张图,表示的是这个序列:
但是,当前的问题的值域是
动态开点
这应该是线段树最为精妙的思想了。很多时候线段树中并不是每一个点都能用到,权值树中更是有大把的空节点,如果每一个都要占用内存,太浪费了。
使用了动态开点,我们不需要建树,每一次的加或者减都会最多创造出 u=++cnt 就好了。
如果是上面那个序列,维护后大概的形状长这样:
可持久化操作
可持久化的权值线段树,也就是主席树,也是一个省空间的技巧。以单点修改为例子,如果我们此时需要添加一个权值进去,需要更新的节点为
大概的形状长这样:
有了这两个操作,相信例题就不在话下了,但是我们要思考一下,为什么线段树(这里是权值线段树)可以支持这样的操作?
answer : 权值线段树结构的统一性
什么叫统一性?也就是说,任意两颗权值线段树的形态是一样的,都是根据区间进行划分的,每一个位置所包含的信息是一个东西。任意两棵树的任意相同位置所代表的节点都是维护一个值。
因此,权值线段树具有 可加减性 ,这代表这权值线段树可以完成前缀累加或者是差分等一系列操作。这些都是平衡树比不了的,因此权值线段树的应用范围更广,而且思路更加巧妙,像数字一样满足结合律与交换律。
比如线段树合并/分裂、树套树,或者是实际应用上的扫描线、逆序对,最重要的也就是本文所提到的
2.\text{Kth} 问题
先从一般情况的入手,即带修改的情况。
例
P3380 【模板】二逼平衡树
一个长为
n 的序列A ,有n 个单点修改或者是查询给定区间\left[L_i,R_i\right] 的第k小数字的操作。
我们刚刚分析的是全局情况,也就是不需要维护这些数字一开始的位置,只需要往一个权值树里面加就好了。但是现在题目要求我们只求一段区间的,难道每次问一次我们都要重新把这些数字添加进去吗?
显然不是,但是如果我们使用一种方法,让我们可以高效率的找到很多颗权值线段树,使他们的并集可以表示出原有区间的所有数字(注意这里用到了权值线段树的可加性),那么每次查询的时候直接加就好了。对于修改操作,我们每次找到包含了该节点的线段树直接改就好了。这要如何实现呢?
你或许会说,树套树!没错,但是树套树是如何实现的?(我们这里使用树状数组套权值线段树解释)
我们知道,树状数组可以在把
如图,这是树状数组的形态。我们只需要将平常的数字累加换成权值线段树累加就好了,对应的区间就是权值线段树中包含数字的范围。
空间复杂度:
时间复杂度:
如果是特殊情况即静态区间第k小呢,能不能优化一点时空?
例
P3834 【模板】可持久化线段树 2
一个长为
n 的序列A ,有n 次查询给定区间\left[L_i,R_i\right] 的第k小数字。
如果说我们在一般不带修改问题中,为了快速获取一段区间,最快的结构是什么?答案呼之欲出 ------ 前缀和 。
也就是说,前缀和可以
这样一来,主席树可以完美契合前缀和的思想,每次
例
咱们来一点不一样的题目
P2633 Count on a tree
树上静态链上第k小,数据范围
10^5 。 参考代码
既然是区间第k小,咱们也来考虑把 例
树上两点
于是这道题写一个树剖求
小结
因为 例
因为 例
而 例
3.一些习题
-
P3810 三维偏序(陌上花开)
-
P3369 【模板】普通平衡树
-
P3332 [ZJOI2013]K大数查询
-
P2617 Dynamic Rankings
P1903 [国家集训队] 数颜色 / 维护队列
维护的东西开始不一样了,仔细考虑一下吧。