打脸了...Splay其实有两种用法,第一个是常数奇大的平衡树
而第二个就厉害了,Splay可以对区间进行操作
具体是怎么个意思呢,我们来看这样一件事情
对于一个数列,我们用Splay维护它的下标
然后我们进行下面的Split操作
1.将l-1旋转到根
2.将r+1旋转到l-1的右儿子
令a为r+1的左子树
然后我们惊奇的发现a这棵子树表示了区间[l,r]
然后...我们就可以对a为所欲为了
当然要注意,l-1指的是数值,而不是点,所以我们需要借用Splay作为平衡树时的一个函数:find()来找到l-1存在哪个位置
然后...我们就可以为所欲为啦
1. 插入、删除:
对于插入操作,我们可以将x转到根部,再将x+1转到x下方然后在x+1的左子树中插入新节点即可。
那么类似的对于删除,我们也可以先将x-1转到根部,x+1转到根下方,那么x就是x+1的左子树,直接删除即可~
2. 询问:
对于询问区间(x,y)的最值,只需将x-1转到根,然后将y+1转到x-1的下方,于是我们需要维护的区间就在y+1的左子树的所有点的集合里了,直接输出节点信息即可。
3. 翻转、区间增加:
和询问类似,先将x-1转到根,然后将y+1转到x-1的下方,然后对y+1的左子树打标记即可~,注意及时更新标记。
4. 滚动:
可以发现,滚动某个区间就等价于交换区间的两部分,我们设这个中点为z,那么我们的目的就是交换(x, z) 和 (z+1, y), 我们可以先将z转到根,然后将y+1转到z的下方,于是y+1的左子树就对应了区间(z+1,y)然后我们将这一段切下来,继续将x-1转到根,再将x转到x-1下方,最后将区间(z+1, y)接到x-1的左边即可。
最后一个问题,怎么输出呢?
注意到我们建Splay的时候,其实它的中序遍历就是原数组,我们写一个递归的print()函数就可以了...
之前还一直以为Splay只是一个平衡树...
真是Naive!