1. 程式人生 > >☆ [ZJOI2006] 書架 「平衡樹維護數列」

☆ [ZJOI2006] 書架 「平衡樹維護數列」

insert targe play amp bottom https efi 查詢 tdi

題目類型:平衡樹

傳送門:>Here<

題意:要求維護一個數列,支持:將某個元素置頂或置底,交換某元素與其前驅或後繼的位置,查詢編號為\(S\)的元素的排名,查詢排名第\(k\)的元素編號

解題思路

可以說是平衡樹維護數列的入門題。當平衡樹在維護數列時,關鍵字是在數列中的排名。因此中序遍歷即為當前數列。註意在平衡樹維護數列中,會涉及到兩個編號。一個編號是這個節點在平衡樹內的編號,一般外界是不會直接訪問的。另一個是題目賦予的編號,代表這個位置數列上對應的值。外部編號即為一個附加值。當我們需要找到外部編號為\(S\)的元素,好像比較麻煩。此時,我們需要多開一個數組\(pos\),令\(pos[idx[o]]=o\)

,相當於是\(idx\)數組的逆運算。在知道一個外部編號時,能夠迅速找到其所對應的節點編號。然後就可以對其進行直接操作了

至於前驅後繼交換,我們只需要交換這兩個節點所對應的外部編號以及更新\(pos\),沒有必要交換平衡樹內的節點。

Code

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
using namespace std;
typedef long long ll;
const int MAXN = 80010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,M,S,T;
char opt[10];
int idx[MAXN],pos[MAXN];
struct Splay{
    int fa[MAXN],ch[MAXN][2],size[MAXN],num_node,rt;
    inline void update(int x){
        size[x] = 1;
        if(ch[x][0]) size[x] += size[ch[x][0]];
        if(ch[x][1]) size[x] += size[ch[x][1]];
    }
    inline bool rson(int f, int x){
        return ch[f][1] == x;
    }
    inline void rotate(int x){
        int f = fa[x], gf = fa[f];
        bool p = rson(f, x), q = !p;
        if(!gf) rt = x; else ch[gf][rson(gf,f)] = x;
        fa[x] = gf;
        ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
        ch[x][q] = f, fa[f] = x;
        update(f), update(x);
    }
    inline void splay(int x, int target){
        int f,gf;
        while(fa[x] != target){
            f = fa[x], gf = fa[f];
            if(gf == target){
                rotate(x);
                break;
            }
            if(rson(gf,f) ^ rson(f,x)) rotate(x); else rotate(f);
            rotate(x);
        }
    }
    inline void init(int id){
        if(!rt){
            rt = ++num_node;
            idx[num_node] = id;
            pos[id] = num_node;
            size[num_node] = 1;
            return;
        }
        int pre_rt = rt;
        rt = ++num_node;
        ch[rt][0] = pre_rt;
        fa[pre_rt] = rt;
        size[rt] = size[pre_rt] + 1;
        idx[rt] = id;
        pos[id] = rt;
    }
    inline void top(int s){
        int o = pos[s];
        splay(o, 0);
        if(!ch[rt][0] && !ch[rt][1]) return;
        int p = ch[rt][1];
        if(!p){
            ch[rt][1] = ch[rt][0];
            ch[rt][0] = 0;
            splay(ch[rt][1], 0);
            return;
        }
        while(ch[p][0]) p = ch[p][0];
        splay(p, rt);
        ch[p][0] = ch[rt][0];
        fa[ch[rt][0]] = p;
        ch[rt][0] = 0;
        update(p), update(rt);
    }
    inline void bottom(int s){
        int o = pos[s];
        splay(o, 0);
        if(!ch[rt][0] && !ch[rt][1]) return;
        int p = ch[rt][0];
        if(!p){
            ch[rt][0] = ch[rt][1];
            ch[rt][1] = 0;
            splay(ch[rt][0], 0);
            return;
        }
        while(ch[p][1]) p = ch[p][1];
        splay(p, rt);
        ch[p][1] = ch[rt][1];
        fa[ch[rt][1]] = p;
        ch[rt][1] = 0;
        update(p), update(rt);
    }
    inline int ask(int s){
        int o = pos[s];
        splay(o, 0);
        return size[ch[rt][0]];
    }
    inline int query(int k){
        int o = rt;
        while(o){
            if(size[ch[o][0]] >= k){
                o = ch[o][0];
            }
            else if(size[ch[o][0]] + 1 < k){
                k -= size[ch[o][0]] + 1;
                o = ch[o][1];
            }
            else{
                return idx[o];
            }
        }
        return -1;
    }
    inline void insert(int S, int T){
        if(T == 0) return;
        splay(pos[S], 0);
        if(T == -1){
            int o = ch[rt][0];
            while(ch[o][1]) o = ch[o][1];
            splay(o, rt);
            swap(idx[rt], idx[o]);
            pos[idx[rt]] = rt, pos[idx[o]] = o;
            update(o), update(rt);
        }
        if(T == 1){
            int o = ch[rt][1];
            while(ch[o][0]) o = ch[o][0];
            splay(o, rt);
            swap(idx[rt], idx[o]);
            pos[idx[rt]] = rt, pos[idx[o]] = o;
            update(o), update(rt);
        }
    }
}qxz;
int main(){
    scanf("%d %d", &N, &M);
    for(int i = 1; i <= N; ++i){
        scanf("%d", &S);
        qxz.init(S);
    } 
    while(M--){
        scanf("%s %d", opt, &S);
        if(opt[0] == 'T'){
            qxz.top(S);
        }
        if(opt[0] == 'B'){
            qxz.bottom(S);
        }
        if(opt[0] == 'A'){
            printf("%d\n", qxz.ask(S));
        }
        if(opt[0] == 'Q'){
            printf("%d\n", qxz.query(S));
        }
        if(opt[0] == 'I'){
            scanf("%d", &T);
            qxz.insert(S,T);
        }
    }
}

☆ [ZJOI2006] 書架 「平衡樹維護數列」