0XFF 前言
*如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽!
0X1F 这个东西有啥用?
树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 树套树------树状数组套可持久化线段树,但是 线段树套平衡树 更加容易理解,更加便于新手理解,所以一般也作为树套树的入门类别。
对于静态区间\(K\)大,我们可以用小巧精悍的主席树来做,也可以用强大无比的\(Splay\)来做。如果带修改,主席树就无能为力了,\(Splay\)也会变得很棘手难打。如果用普通线段树,每个节点都有着一课包含子节点的\(Splay\),对于一个区间,直接调用线段树上的\(Splay\)就迎刃而解了。这时的\(Splay\)不是对全局,而是只对这个线段树节点代表的区间。
当然,树套树------线段树套平衡树并不是那么的好打,还是要动纸笔 and 动脑筋。缺点也是有的:因为要打\(Splay\)和线段树,模板的码量就有 \(150\) 行!因为线段树本来就是易手滑的数据结构,稍不留神可能会让你调上好久!另外,因为\(Splay\)的常数极大,再这么通过线段树一罩,效率就下来了许多,常数巨大无比......总之 树套树 是一个很强的数据结构,但是如果题目不是强制在线的话,\(CDQ\)分治和整体二分会将树套树吊起来打!
------------Qiuly
0X2F 这个东西怎么实现?
首先,线段树套平衡树可以解决的一般问题如下:
-
- 查询 \(k\) 在区间 \(l,r\) 内的排名
-
- 查询区间 \(l,r\) 内排名为 \(k\) 的值
-
- 修改某一位置上的数值
-
- 查询 \(k\) 在区间 \(l,r\) 内的前驱
-
- 查询 \(k\) 在区间 \(l,r\) 内的后继
-
- 修改区间 \(l,r\) 的值(集体加减)(不会)
............
我们今天来讲讲前五个基础操作怎么实现(我只会前五个操作)
0X2f-1 查询 \(k\) 在区间 \(l,r\) 内的排名
我们先将一个外面的线段树画下来:
(叶子节点中的数字是序列各个元素的权值)
假设我们现在要查询区间 \(3,8\) 中 \(5\) 的排名。
查询一个数的排名,很显然,就是查询这个区间内有多少个数比 Ta 小,然后在+1(即自己)。
那怎么查询 \(3,8\) 区间内有多少个数比他小呢?\(3,8\) 不是整个线段树节点啊。
我们可以将它分成若干个线段树节点来处理。
Code:
inline int Splay_rank(int i,int k){//i表示以线段树的i号节点为根的Splay
int x=rt[i],cal=0;//板子就不再赘述了
while(x){
if(v[x]==k)return cal+((ch[x][0])?s[ch[x][0]]:0);