1. 程式人生 > 其它 >平衡樹(三)——FHQ Treap

平衡樹(三)——FHQ Treap

目錄

前言

上文介紹了普通的平衡樹,它簡單(奇怪,鬼畜)的旋轉操作確實死難寫也難調(剛寫掛一個),於是跑去學了一個不用旋轉的平衡樹,無旋 \(Treap (FHQ~~Treap)\)

只需要兩個操作達到 \(splay\) 全部功能 ?? 太炫酷了

概況

\(FHQ~~Treap\) 和普通的 \(Treap\) 一樣每個節點維護兩個值,一個是權值,一個是隨機值

但是它不再是用旋轉來維護,而是通過 \(split\)\(merge\) 進行維護

操作

split(分樹)

把一個 \(Treap\) 分成兩個

兩種:按權值分,按子樹大小分

複雜度 \(O(log n)\)

按權值分

把權值小於 \(k\) 的節點都分到一棵樹中,其餘的點都分到另一棵樹中

如果當前節點權值小於 \(k\) 那麼它的左子樹都會分到一棵樹內,然後向右孩子查詢

否則該節點的右節點都會分到另一個子樹內,然後向右查詢

    void split(int p, int k, int &x, int &y) {
        if (!p) x = y = 0;
        else {
            if (val[p] <= k) x = p, split(rs(p), k, rs(p), y);
            else y = p, split(ls(p), k, x, ls(p));
            update(p);
        }
    }

按子樹大小分

把一棵樹分成兩棵樹,其中一棵的大小為 \(k\)

\(Treap\)\(Kth\) 操作類似

如果當前點的左子樹大小大於 \(k\) ,向左子樹繼續查詢

否則的話該點的左子樹一定在大小為 \(k\) 的樹中,然後使右子樹分出 \(k - siz[p] - 1\) 大小的子樹

    int split(int p, int k, int &x, int &y) {
       if(!p) x = y = 0;
       else {
          if(k <= siz(ls(p)))
            y = p, split(ls(p), k, x, ls(p));
          else 
            x = p, split(rs(p), k - siz[ls(p)] - 1, rs(p), y);
          update(p);
       }
    }

merge(合併)

先咕著,明天寫……