[總結] 無旋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的時候可能考慮到空子樹的狀況,爲避免空子樹的影響
須要一個初始化.遞歸

相關文章
相關標籤/搜索