[总结] 无旋treap

- 导语 -

顾名思义就是没有旋转操做的treap.
仍是很好打的.
毕竟旋转操做旋转上天.html

- 学习 -

两个核心操做: splitmerge函数

split是将一棵树分红两棵树的操做.
注意这里的要求是对于肯定的树,将其前k个点分红新树, 剩下的点变成另外一颗新树,所以可能出现多个切割的地方.
对于一个节点来讲,咱们必然只会处理它的一颗子树,所以用递归去找处理的子树就好了.
返回时对于每个点更新一下它被处理的那颗子树.
函数的返回值是两颗子树的根.
具体看代码吧学习

define pii pair<int,int>
define mp make_pair

pii split(int rt, int k) { //对于根为rt的树,将它前k个点裂成一棵树A,剩下的点成为树B

  if (!rt) return mp(0, 0);
  
  pii tmp;
  pushdown(rt);
  
  if (k > S[C[rt][0]]) { //处理右子树
    tmp = split(C[rt][1], k - S[C[rt][0]] - 1);
    //tmp表示右子树分裂出来的两棵树(A,B),
    //其中左边(A)的是当前rt的新的右子树
    C[rt][1] = tmp.first; pushup(rt); tmp.first = rt;
    //更新rt, 而后将rt做为一个新的左子树,
    //原右子树分裂出来的右边的新树(B)做为新的右子树,
    //将这颗新树返回
    
  }
  else { //处理左子树
    tmp = split(C[rt][0], k);
    C[rt][0] = tmp.second; pushup(rt); tmp.second = rt;
  }
  
  return tmp;

}

merge便是将两颗树合并的操做, 注意这里合并的树(A,B)要求max_value(A) < min_value(B),这样把AB一左一右相接(即保证B的每个节点都在A的右边)便保证了权值的有序,咱们就只要维护堆的性质了.(显然split分出来的两颗树就知足这样的性质)ui

int merge(int ra, int rb) { //返回新树的根

  if (!ra) return rb;
  if (!rb) return ra; //有一颗空树,直接合并
  
  pushdown(ra);
  pushdown(rb);

  if (KEY[ra] < KEY[rb]) { //ra的key值较小,维护小根堆的话要放在上面
    C[ra][1] = merge(C[ra][1], rb);
    //默认rb是接在右边的树,所以rb必然会接进ra的右子树中
    pushup(ra); return ra;
    //不要忘记更新
  }
  else {
    C[rb][0] = merge(ra, C[rb][0]);
    pushup(rb); return rb;
  }

}

- 单点操做 -

这里是题目.
单点操做基本都能靠merge+split完成.
好比这题只需加上splay中同样的getkth(找到第k个数), findkth(找到数A的位置),
那么:
insert=getkth(findkth+getkth)+split+merge
delete=getkth(findkth+getkth)+split+merge
单点插入删除也可用(merge)(split)完成.code

- 区间操做 -

这里是题目.
其实和单点操做没什么区别...
区间的插入删除也是使用(merge)(split)完成.
删除好说,可是注意插入时须要咱们先建好一颗子树再merge.
因而又有了一个build函数.
咱们能够一个一个把点插到新树中去(一开始有一颗空树).
那么每次插入的点必然在树的最右端.htm

而后开始维护小根堆的性质.
考虑root -> right son -> right son ... 这样一条链, 咱们先把新点接在这条链最下面,
而后找到其中深度最小的一个key值大于大于点的节点,把以它为根的子树当作新点
的左子树, 而后用新点代替它原来的位置就能够了.(至关于把新点沿着链一直向上旋)
可是须要注意排布在这条链上的树是没有维护(pushup/update)过的, 所以每次
寻找到要被移到新点下面的点都须要一次pushup, 最后再给仍在链上的点来一发pushup.
由于每次加入的点都在链上, 能够证实每一个点都会(在它的全部子树以后)通过一次pushupblog

还有一个须要注意的点是splay中的虚点.
无旋treap并不须要虚点,可是在pushup的时候可能考虑到空子树的状况,为避免空子树的影响
须要一个初始化.递归

相关文章
相关标签/搜索