羅区P3369 [テンプレート]一般的なバランスの取れたツリーtreap

URL:https://www.luogu.org/problem/P3369

質問の意味:

各$ O(LOGN)(1 \当量のn \の当量の1E6)$、以下の機能のデータ構造の調製:

シーケンス内の番号を削除し、2;第三に、大型の$ K $を見つける;第四に、呼掛け$ $ Kの多数;、シーケンス番号に挿入されるVを、X $ $は、前駆体、6を見つけます$のx $の後継者を見つけます。

ソリューション:

明らかに、二分探索木は、このタスクを達成することができますが、最悪の場合には、バイナリツリーがチェーンに退化だろう、それはタイムアウトしますので、我々は書くことがより簡単でバランスの取れたバイナリツリーを、必要とする、速いスピードでtreapです。treap非スピンに分け、treap treapスピン、前者は高速ですが、遅い持続性、が、永続的なサポートをサポートしていません。

まず、スピンtreapがあります

Treap右ノードはバランスをとるために、バイナリの性質の値を維持し、スタックを維持するために、追加のプロパティの数でバランスが取れており、この番号は、各ノードに対応する乱数であることが必要です。回転乱数に回転するときに示すように、左右の手に分けます:

(参考ブログ:https://blog.csdn.net/K346K346/article/details/50808879

左と右の手

明らかに右のサブツリー、右利きの子供がルートになって、元の樹木の根の左、左サブツリー、Lの共感の元のルートへの元の左のサブツリーのルートです。バイナリツリーを回転させた後、変更の性質を証明することは容易です。

挿入されたとき、第一挿入ポイントを見つけ、再び回転させました。

より複雑な削除は、削除、検索し、削除後のサブツリーのルートとしてサブツリーを観察し、ランダムな値を選択する点を削除し、ノードの回転により葉を除去するための移動後削除します。

コードを見て、理解しやすい照会操作。

ACコード:

#include <ビット/ STDC ++ H> 
名前空間STDを使用して、
const int型MAXN = 100005; 
const int型INF = 0x3f3f3f3f。
構造体Treap 
{ 
    構造体ノード
    { 
        int型のVal、RND、LC、RC、サイズ、NUM。
    }。
    int型CNT = 0; 
    ノードTR [MAXN]。
    ボイドのinit()
    { 
        CNT = 0。
    } 
    int型_rand()
    { 
        静的INTシード= 12345。
        シード=(INT)シードを返す* 482711LL%2147483647。
    } 
    ボイド押し上げ(INT P)
    { 
        TR [P] .size = TR [TR [P]を得た。LC] .size + T R [TR [P] .RC] .size + TR [P] .nu​​m。
    } 
    ボイド右(INT&K) 
    {
        INT TMP = T R [k]を得た。LC。
        T R [k]を得た。LC = TR [TMP] .RC。
        TR [TMP] .RC = K。
        TR [TMP] .size = TR [K] .size。
        突き上げ(K)。
        K = TMP。
    } 
    左空隙(INT&K)
    { 
        int型TMP = TR [K] .RC。
        TR [K] .RC = TR [TMP]を得た。LC。
        TR [TMP]を得た。LC = K。
        TR [TMP] .size = TR [K] .size。
        突き上げ(K)。
        K = TMP。
    } 
    ボイドインサート(INT&P、INT X)
    { 
        IF(P == 0)
        { 
            P = ++ CNT。
            TR [P] .val = xと; 
            TR [P] .nu​​m = TR [P] .size = 1。
            返します。
            TR [P]を得た。LC = TR [P] .RC = 0。
            TR [P] .rnd = _rand()。
        } 
        ++ TR [P] .size。
        もし(x == TR [P] .val)
            ++ TR [P] .nu​​m。
        他の場合(X <TR [P] .val)
        { 
            インサート(TR [P]を得た。LC、X)。
            IF(TR [TR [P]を得た。LC] .rnd <TR [P] .rnd)
                右(P)。
        } 
        そうであれば(X> TR [P] .val)
        { 
            インサート(TR [P] .RC、X)。
            (TR [TR [P] .RC] .rnd <TR [P] .rnd)であれば
                、左(P)。
        } 
    } 
    ボイドデル(INT&P、INT X)
    { 
        IF(P == 0)
            のリターン; 
        IF(TR [P] .val == X)
        { 
            場合(TR [P] .nu​​m> 1) 
                --tr [P] .nu​​m、 - TR [P] .size。
            { 
                (TR [P]を得た。LC == 0 || TR [P] .RC == 0)であれば
                    、P = T R [P]を得た。LC + T R [P] .RC。
                そうであれば(TR [TR [P]を得た。LC] .rnd <TR [TR [P] .RC] .rnd)
                    右(P)、デル(P、x)は、
                (TR [TR [P]を得た。LC] .rnd> TR [TR [P] .RC] .rnd)もしそうでなければ
                    、左(P)、デル(P、x)は、
            } 
        } 
        そうでなければ(TR [P] .val <x)の場合
            --tr [P] .size、デル(TR [P] .RC、X)。
            --tr [P] .size、デル(TR [P]を得た。LC、X)。
    } 
    INT queryrnk(INT&P、INT X)
    { 
        (p == 0)場合
            0を返します。
        そうであれば(TR [P] .val == X)
            TR [TR [P]を得た。LC] .size + 1を返します。
        そうであれば(TR [P] .val <x)を
            返すTR [TR [P]を得た。LC] .size + T R [P] .nu​​m + queryrnk(TR [P] .RC、X)。
            戻りqueryrnk(TR [P]を得た。LC、X)。
    } 
    INT querynum(INT&P、INT RNK)
    { 
        IF(P == 0)
            戻り0; 
        IF(TR [TR [P]を得た。LC] .size> = RNK)
            戻りquerynum(TR [P]を得た。LC、RNK)。
        rnk- = TR [TR [P]を得た。LC] .size。
        IF(RNK <= TR [P] .nu​​m)
            戻りTR [P] .val。
        rnk- = TR [P] .nu​​m。  
        querynum(TR [P] .RC、RNK)を返します。
    } 
    int型queryfront(INT&P、INT X)
    {
        もし(P == 0)
            戻り-INF。
        IF(TR [P] .val <x)を
            リターンMAX(TR [P] .val、queryfront(TR [P] .RC、X)); 
        そうであれば(TR [P] .val> = X)
            リターンqueryfront(TR [P]を得た。LC、X)。
    } 
    INT queryback(INT&P、INT X)
    { 
        IF(P == 0)
            戻りINF。
        IF(TR [P] .val> X)
            リターン分(TR [P] .val、queryback(TR [P]を得た。LC、X)); 
        そうであれば(TR [P] .val <= x)の
            戻りqueryback(TR [P] .RC、X)。
    } 
}。
int型のPOS。
TreapのTR; 
メインINT()
{ 
    int型のn; 
    scanf関数( "%のD"、&N); 
    int型M、K。
    tr.init();
    (; iがN <++ iが0 = INT)のために
    {
        scanf関数( "%dの%のD"、&M、およびK); 
        IF(M == 1)
            tr.insert(POS、K)。
        他(M == 2)もし
            tr.del(POS、K)。
        他(M == 3)場合
            のprintf( "%d個の\ n"、tr.queryrnk(POS、K))。
        他(M == 4)場合
            のprintf( "%d個の\ n"、tr.querynum(POS、K))。
        他(M == 5)場合
            のprintf( "%d個の\ n"、tr.queryfront(POS、K))。
        他(M == 6)場合
            のprintf( "%d個の\ n"、tr.queryback(POS、K))。
    } 
    0を返します。
}

  

 

 

 

おすすめ

転載: www.cnblogs.com/Aya-Uchida/p/11361489.html