루오 구 P3369 [템플릿] 일반 균형 트리 treap

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

질문의 의미 :

다음 함수 각각 $ O (logn) 내의 데이터 구조 (1 \ 당량의 N \의 당량의 1E6) $의 제조 :

순서 번호를 삭제 두; 셋째, 큰 $ k에 $으로 찾을 넷째, 심문 $ $ K 다수; A는, 일련 번호에 삽입되어 V를 X $ $는 전구체 여섯 발견 $ X의 $ 후계자를 찾을 수 있습니다.

해결 방법 :

물론, 이진 검색 트리가이 작업을 수행 할 수 있지만, 최악의 경우, 이진 트리가 체인으로 변질 것, 그것은 시간 초과, 그래서 우리가 쓰기 더 쉽게 균형 이진 트리가 필요, 빠른 속도는 treap입니다. treap 비 스핀으로 나누어 treap treap 스핀, 전자는 빠르지 만 느린 지속성,하지만 지속적인 지원을 지원하지 않습니다.

첫째, 스핀 treap있다

Treap 오른쪽 노드는이 번호는 각 노드에 대응하는 임의의 수이고,는이 스택을 유지하기 위해 부가적인 특성들에 의해 균형 것이 필요하고, 균형을 위해, 진 본성의 값을 유지한다. 회전 난수 회전 할 때와 같이, 좌측 및 우측으로 분할 :

(참고 블로그 : https://blog.csdn.net/K346K346/article/details/50808879 )

왼쪽 및 오른쪽

물론 오른쪽 서브 트리, 오른 손잡이 아이가 루트가 원래 나무 뿌리의 왼쪽, 왼쪽 서브 트리, L 공감의 원래 루트로 원래의 왼쪽 서브 트리의 루트입니다. 이진 트리를 회전 한 후 변화의 본질을 증명하기 쉽다.

삽입 할 때, 먼저 삽입 지점을 찾은 다음 다시 회전.

더 복잡한 제거는 삭제 찾아 삭제 후 하위 트리의 루트로하는 서브 트리를 관찰 임의의 값을 선택 포인트를 삭제 한 다음 노드의 회전에 의해 잎을 제거 할 수있는 이동 후 삭제 될 수 있습니다.

쉽게 쿼리 작업은 코드를보고, 이해합니다.

AC 코드 :

#INCLUDE <비트 / stdc ++ H.> 
네임 스페이스를 사용하여 표준; 
CONST의 INT의 MAXN = 100005; 
INF = CONST INT 0x3f3f3f3f; 
구조체 Treap 
{ 
    구조체 노드 
    { 
        INT 계산해 RND, LC, RC, 크기, NUM; 
    }; 
    INT CNT = 0; 
    노드 TR [MAXN]; 
    공극 초기화 () 
    { 
        CNT = 0; 
    } 
    INT의 _rand () 
    { 
        정적 INT 시드 = 12345; 
        시드 = (int)에 시드를 반환 482711LL % * 2147483647; 
    } 
    공극 팔 굽혀 펴기 (INT의 P) 
    { 
        TR [P] 크기는 TR = [그럴 [피] .lc] 크기는 + TR [TR [P] .RC] 크기는 TR + [P] .num; 
    } 
    공극 오른쪽 (INT & k) 
    {
        INT TMP = TR [K] .lc; 
        TR [K] = .lc TR [TMP] .RC; 
        TR [TMP] .RC = K; 
        TR [TMP] 크기는 TR = [K] 크기는; 
        팔 굽혀 펴기 (K); 
        k는 TMP를 =; 
    } 
    공극 왼쪽 (INT & k) 
    { 
        INT TMP = TR [K] .RC; 
        TR [K] = .RC TR [TMP] .lc; 
        TR [TMP] .lc = K; 
        TR [TMP] 크기는 TR = [K] 크기는; 
        팔 굽혀 펴기 (K); 
        k는 TMP를 =; 
    } 
    공극 인서트 (INT & P, INT의 X) 
    { 
        (p == 0) 경우에 
        { 
            p = CNT ++; 
            그럴 [피] = .val의 X; 
            그럴 [피] .num TR = [P] = 크기는 1; 
            TR [P] .lc TR = [P] .RC = 0;
            TR [P] = .rnd _rand (); 
            반환;
        } 
        ++ TR [P] 크기는; 
        (X == TR [P] .val 있으면) 
            ++ TR [P] .num; 
        다른 경우 (X <TR [P] .val) 
        { 
            인서트 (TR [P] .lc, X); 
            (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) 
    { 
        경우 (p == 0) 
            돌려 준다 
        경우 (TR [P] == .val의 X)를 
        { 
            의 경우 (TR [P] .num> 1)
                --tr [P] .num - TR [P] 크기는; 
            { 
                경우 (TR [P] .lc == 0 || TR [P] .RC == 0) 
                    p = TR [P] .lc TR + [P] .RC; 
                다른 경우 (TR [TR [P] .lc] .rnd <TR [그럴 [피] .RC] .rnd) 
                    오른쪽 (p), 델 (p, X); 
                다른 경우 (TR [TR [P] .lc] .rnd> TR [그럴 [피] .RC] .rnd) 
                    왼쪽 (p), 델 (p, X); 
            } 
        } 
        다른 경우 (TR의 [피] .val <x) 
            --tr [P] 크기는, 델 (TR [P] .RC, X); 
        다른 
            --tr [P] 크기는, 델 (TR [P] .lc, X); 
    } 
    INT queryrnk (INT & P, INT의 X) 
    {  
        경우 (p == 0)
            창 0; 
        다른 경우 (TR [P] == .val의 X)
            TR [TR [P]를 .lc] + 리턴 크기는 1; 
        (TR의 [p를] .val <x) 다른 경우 
            TR [TR [P]를 .lc] 복귀 크기는 TR + [P] + .num queryrnk (TR [P] .RC, X); 
        다른 
            리턴 queryrnk (TR [P] .lc, X); 
    } 
    INT querynum (INT & P, INT RNK) 
    { 
        경우 (p == 0) 
            복귀 0; 
        경우 (TR [TR [P] .lc] 크기는> = RNK) 
            복귀 querynum (TR [P] .lc, RNK); 
        rnk- = TR [그럴 [피] .lc] 크기는; 
        경우 (RNK <TR = [P] .num) 
            복귀 그럴 [피] .val; 
        rnk- TR = [P] .num;  
        querynum (TR [P] .RC, RNK)을 반환; 
    } 
    INT queryfront (INT & P, INT (X)의) 
    {
        (p == 0)의 경우
    tr.init ();
            -inf 반환; 
        경우 (TR의 [피] .val <x) 
            복귀 맥스 (TR [P] .val, queryfront (TR [P] .RC, X)); 
        다른 경우 (TR의 [피] .val> = x)를 
            리턴 queryfront (TR [P] .lc, X); 
    } 
    INT queryback (INT & P, INT의 X) 
    { 
        경우 (p == 0) 
            복귀 INF 단계; 
        경우 (TR의 [피] .val> X) 
            분을 반환 (TR [P] .val, queryback (TR [P] .lc, X)); 
        다른 경우 (TR [P] .val <= x)를 
            리턴 queryback (TR [P] .RC, X); 
    } 
}; 
INT의 POS; 
Treap의 TR; 
INT의 main () 
{ 
    INT 않음; 
    scanf와 ( "%의 D", N); 
    INT의 m, K; 
    (0 = 1을 나타내는 int i가 N <; I ++) 
    {
        scanf와 ( "%의 D % d에", m, k)를; 
        경우 (m == 1) 
            tr.insert (POS, K); 
        그렇지 않은 경우 (m을 == 2) 만약 
            tr.del (POS, K); 
        다른 경우 (m을 == 3) 
            의 printf ( "% D \ 없음"tr.queryrnk (POS, K)); 
        다른 경우 (m을 == 4) 
            의 printf ( "% D \ 없음"tr.querynum (POS, K)); 
        다른 경우 (m을 == 5) 
            의 printf ( "% D \ 없음"tr.queryfront (POS, K)); 
        다른 경우 (m을 == 6) 
            의 printf ( "% D \ 없음"tr.queryback (POS, K)); 
    } 
    0을 반환; 
}

  

 

 

 

추천

출처www.cnblogs.com/Aya-Uchida/p/11361489.html