1.题目描述:点击打开链接
2.解题思路:本题是伸展树的基本题型,不过由于是第一次使用这种数据结构,先补了一下BST和Treap的基础知识,然后才开始学这种数据结构。不难发现,伸展树最基本且最核心的操作就是伸展操作,它能够将一个指定的结点通过旋转操作逐步转为树根。同时由于伸展树本质上也是一种BST,因此同时具备BST的基本功能,比如查询操作。我们每次都把箭头指向的位置作为树根。
首先是建树过程,我们从区间的中间位置开始,把它当做树根,如果m>L,那么递归建立左子树,如果m
下面来谈一谈如何利用伸展树来完成题目中给定的6种操作。
1.add X:要求把从箭头指向的位置到右边第k2个位置的所有数都增加X。显然,我们需要一个lazy标记来完成这一操作,不妨设为add。那么首先把k2位置伸展为树根,这样左子树的所有结点和根就是我们要进行add操作的所有结点。对根的value+add,并将左子树的lazy标记+add即可。
2.reverse:要求把从箭头指向的位置到右边第k1个位置的数反转。首先执行Splay(root,k1),并把它的右子树暂时分开,标记root->flip=1,翻转完毕后再将右子树合并回去。
3.insert X:要求在箭头指向的位置的下一个位置插入X。首先执行Splay(root,1),这样,只需要在root和root->ch[1]之间插入X即可,同时n++。
4.delete:要求删除箭头指向的位置,并把箭头向右移动一位。首先执行Splay(root,1),这样,所有结点都在右子树上,只需要把root设置为右子树的根即可,同时n--。
5.move X:当X==1时,将箭头向左移动一位;当X==2时,将箭头向右移动一位。当X==1时,先执行Splay(root,n),此时所有结点都在左子树上(注意此时a[n]是树根,a[1]已经在左子树上了),把根和左子树分离,同时对左子树执行Splay(tmp,1)(tmp即左子树树根)。然后让左子树成为根的右子树即可,即root->ch[1]=tmp。用同样的方法可以处理右子树。
6.query:输出箭头指向的数字。直接输出root->value即可。
由此,我们成功利用伸展树实现了上述的6种操作。
3.代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include