1. 程式人生 > >7.Bzoj3224: Tyvj 1728 普通平衡樹(Treap)

7.Bzoj3224: Tyvj 1728 普通平衡樹(Treap)

Bzoj3224: Tyvj 1728 普通平衡樹(Treap)

終於自己敲出來了Treap。。。。。。拿來當板子還是挺好用的.
操作1,顯然根據二叉搜尋樹的性質直接建就好了.
操作2,如果有兩個兒子,則把這個點下旋下去,直到只有一個兒子或者沒有.
操作3,查詢比他小的數,記錄一個size,表示這個點有多少個兒子.
操作4,排名為x , 那麼就有x - 1個數小於等於這個數.
操作5,直接去min再根據二叉搜尋樹的性質,就ok了.
操作6,同操作5.


#include <iostream>
#include <cstdio>
#include <algorithm>
#define rep(i , x, p) for(int i = x;i <= p;++ i)
#define sep(i , x, p) for(int i = x;i >= p;-- i)
#define gc getchar()
#define pc putchar
using namespace std;
const int inf = 1e9;
const int maxN = 100000 + 7;

inline int read() {int x = 0,f = 1;char c = gc;while(c < '0' || c > '9') {if(c == '-')f = -1;c = gc;}while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = gc;}return x * f;}
void print(int x) {if(x < 0) pc('-') , x = -x;if(x >= 10) print(x / 10);pc(x % 10 + '0');}

int ch[maxN][2] , pos[maxN], size[maxN], key[maxN], rt, cnt;

void up(int i) {size[i] = size[ch[i][0]] + size[ch[i][1]] + 1;return ;}

void spin(int &i , int p) {
    int tmp = ch[i][p];
    ch[i][p] = ch[tmp][!p];ch[tmp][!p] = i;up(i);i = tmp;up(i);
}

void Insert(int &i , int x) {
    if(!i) {
        ++ cnt;i = cnt;
        size[i] = 1;pos[i] = rand();
        key[i] = x;
        return ;
    }
    if(key[i] >= x) {
        Insert(ch[i][0] , x);
        if(pos[i] < pos[ch[i][0]]) spin(i , 0);
    }
    else {
        Insert(ch[i][1] , x);
        if(pos[i] < pos[ch[i][1]]) spin(i , 1);
    }
    up(i);
}

int getrank(int &i , int x) {
    if(!i) return 1;
    if(key[i] >= x) return getrank(ch[i][0] , x);
    return getrank(ch[i][1] , x) + size[ch[i][0]] + 1;
}

int is_rank(int i , int x) {
    if(size[ch[i][0]] == x - 1) return key[i];
    if(size[ch[i][0]] >= x) return is_rank(ch[i][0] , x);
    return is_rank(ch[i][1] , x - size[ch[i][0]] - 1);
}

int pre(int i , int x) {
    if(!i) return -inf;
    if(key[i] < x) return max(pre(ch[i][1] , x) , key[i]);
    return pre(ch[i][0] , x);
}

int nxt(int i , int x) {
    if(!i) return inf;
    if(key[i] > x) return min(nxt(ch[i][0] , x) , key[i]);
    return nxt(ch[i][1] , x);
}

void Dele(int &i , int x) {
    if(key[i] == x) {
        if(ch[i][0] * ch[i][1] == 0) {i = ch[i][0] + ch[i][1];return ;}
        if(pos[ch[i][0]] > pos[ch[i][1]]) {spin(i , 1); Dele(ch[i][0] , x);}
        else {spin(i , 0) , Dele(ch[i][1] , x);} 
    }else {
        if(x < key[i]) Dele(ch[i][0] , x);  
        else Dele(ch[i][1] , x);
    }
    up(i);
}

int main() {
    int n = read() , opt , x;
    rep(i , 1, n) {
        opt = read();x = read();
        if(opt == 1) Insert(rt , x);
        else if(opt == 2) Dele(rt , x);
        else if(opt == 3) print(getrank(rt , x)) , pc('\n');
        else if(opt == 4) print(is_rank(rt , x)) , pc('\n');
        else if(opt == 5) print(pre(rt , x)) , pc('\n');
        else print(nxt(rt , x)) , pc('\n');
    }
    return 0;
}

考察點

Treap的基本操作