「Splay」指针版与数组版模板

Posted qixingzhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「Splay」指针版与数组版模板相关的知识,希望对你有一定的参考价值。

splay总是多打打就熟了,先把板子贴在这里方便查看

Splay的思想还是很简单的,反正就是把每次查询到的都splay到根,维护动态平衡

插入的时候就找到位置,splay到根

删除是最麻烦的,先查找到它并splay到根。然后找到前驱splay到根的左子节点作为根,废掉原先的根节点,然后把右子节点接到前驱的右子树上。

排名只要splay到根输出左子树+1就好了

kth也不难,从根开始,如果不够就往左走,要么是自己,再不行就往右边走。不要忘了k要减掉左子树和cnt

前驱后继只要先插入查一下再删掉就好了

数组版

/*By QiXingzhi*/
#include <cstdio>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 100010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ - && (c < 0 || c > 9)) c = getchar();
    if(c == -) w = -1, c = getchar();
    while(c >= 0 && c <= 9) x = (x << 3) +(x << 1) + c - 0, c = getchar();
    return x * w;
}
struct Splay{
    int ch[MAXN][2], fa[MAXN], val[MAXN], size[MAXN], cnt[MAXN], root, num_node;
    inline bool Son(int f, int x){ return ch[f][1] == x; }
    inline void Update(int x){ size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; }
    inline void Rotate(int x){
        int f = fa[x], gf = fa[f];
        int p = Son(f, x), q = !p;
        ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
        ch[x][q] = f, fa[f] = x;
        fa[x] = gf;
        if(gf != 0) ch[gf][Son(gf,f)] = x; else root = x;
        Update(x), Update(f);
    }
    inline void splay(int x, int target){
        while(fa[x] != target){
            int f = fa[x], gf = fa[f];
            if(gf == target) Rotate(x);
            else{
                if(Son(gf, f) == Son(f, x)) Rotate(f), Rotate(x);
                else Rotate(x), Rotate(x);
            }
        }
    }
    inline void Insert(int v){
        if(root == 0){
            root = ++num_node;
            size[num_node] = cnt[num_node] = 1;
            val[num_node] = v;
            return;
        }
        int p = 0;
        for(int x = root; x != 0; x = ch[x][p]){
            p = v > val[x];
            if(v == val[x]){
                ++cnt[x], splay(x, 0);
                return;
            }
            if(ch[x][p] == 0){
                ch[x][p] = ++num_node;
                fa[ch[x][p]] = x;
                size[ch[x][p]] = cnt[ch[x][p]] = 1;
                val[ch[x][p]] = v;
                splay(ch[x][p], 0);
                return;
            }
        }
    }
    inline void Find(int v){
        int x = root, p;
        for(; x != 0; x = ch[x][p]){
            if(v == val[x]){ splay(x, 0); return; }
            p = v > val[x];
            if(ch[x][p] == 0){ splay(x, 0); return; }
        }
    }
    inline void Delete(int v){
        Find(v);
        if(val[root] != v) return;
        if(cnt[root] > 1){ --cnt[root]; return; }
        if(ch[root][0] == 0 && ch[root][1] == 0){ root = fa[root] = 0; return; }
        if(ch[root][0] == 0){ root = ch[root][1], fa[root] = 0; return; }
        if(ch[root][1] == 0){ root = ch[root][0], fa[root] = 0; return; }
        int l_max = ch[root][0];
        for(; ; l_max = ch[l_max][1]) if(ch[l_max][1] == 0) break;
        splay(l_max, root);
        int pre_root = root;
        root = l_max;
        fa[root] = 0;
        ch[root][1] = ch[pre_root][1];
        if(ch[pre_root][1] != 0) fa[ch[pre_root][1]] = root;
    }
    inline int Pre(int v){
        Insert(v);
        int x = ch[root][0], ans;
        for(;; x = ch[x][1])
            if(ch[x][1] == 0){ ans = val[x]; break; }
        Delete(v);
        return ans;
    }
    inline int Nxt(int v){
        Insert(v);
        int x = ch[root][1], ans;
        for(; ; x = ch[x][0])
            if(ch[x][0] == 0){ ans = val[x]; break; }
        Delete(v);
        return ans;
    }
    inline int Kth(int k){
        int x = root, p = 0;
        for(;;){
            if(size[ch[x][0]] + cnt[x] >= k && size[ch[x][0]] < k) return val[x];
            else if(size[ch[x][0]] >= k) x = ch[x][0];
            else{
                k -= (size[ch[x][0]] + cnt[x]);
                x = ch[x][1];
            }
        }
    }
    inline int Rank(int v){
        Find(v);
        return (size[ch[root][0]] + 1);
    }
}qxz;
int n,opt,x;
int main(){
    n = r;
    while(n--){
        opt = r, x = r;
        if(opt == 1) qxz.Insert(x);
        if(opt == 2) qxz.Delete(x);
        if(opt == 3) printf("%d
", qxz.Rank(x));
        if(opt == 4) printf("%d
", qxz.Kth(x));
        if(opt == 5) printf("%d
", qxz.Pre(x));
        if(opt == 6) printf("%d
", qxz.Nxt(x));
    }
    return 0;
}

指针版

/*This Program is written by QiXingZhi*/
#include <cstdio>
#define  N    (100010)
#define  ll    long long
#define  INF    (0x7f7f7f7f)
#define  read(x)    x=Rd()
#define  Max(a,b)    (((a) > (b)) ? (a) : (b))
#define  Min(a,b)    (((a) < (b)) ? (a) : (b))
#define  FILE_IN(x)    freopen(x".in","r",stdin)
using namespace std;
inline int Rd(){
    char c = getchar(); int x = 0;int w = 1;
    while(c ^ - && (c < 0 || c > 9)) c=getchar();
    if(c == -) w = -1, c = getchar();
    while(c >= 0 && c <= 9) x = (x<<3)+(x<<1)+c-48,c = getchar();
    return x * w;
}
struct Node{
    int val,sz,cnt;
    Node* fa;
    Node* s[2];
    Node(){fa=s[0]=s[1]=NULL; val=sz=cnt=0; }
};
int n,m,opt,x;
Node* tree;
inline bool Rson(Node* a, Node* b){return ((a->s[1])==(b));}
inline int Size(Node* o){
    if(o == NULL) return 0;
    return o->sz;
}
inline void Update(Node* o){
    if(o == NULL) return;
    o->sz = o->cnt + Size(o->s[0]) + Size(o->s[1]);
}
inline void Rotate(Node* x){
    Node *f = x->fa, *gf = f->fa;
    bool p = Rson(f,x),q = !p;
    f->s[p] = x->s[q];
    if(x->s[q] != NULL) x->s[q]->fa = f;
    x->s[q] = f,f->fa = x,x->fa = gf;
    if(gf != NULL) gf->s[Rson(gf,f)] = x; else tree = x;
    Update(x),Update(f);
}
inline void Splay(Node* x, Node* t){
    while(x->fa != t){
        Node *f = x->fa, *gf = f->fa;
        if(gf == t)Rotate(x);
        else{
            bool p = Rson(f,x);
            if(Rson(gf,f) ^ Rson(f,x)) Rotate(x),Rotate(x);
            else Rotate(f),Rotate(x);
        }
    }
}
inline void Insert(int x){
    bool b;
    if(tree == NULL){
        tree = new Node();
        tree->val = x, tree->cnt = tree->sz = 1;
        return;
    }
    for(Node* o = tree; o != NULL; ){
        b = x >= o->val;
        if(o->val == x){
            ++o->cnt;
            Splay(o,NULL);
            return;
        }else{
            if(o->s[b] == NULL){
                o->s[b] = new Node();
                o->s[b]->fa = o;
                o->s[b]->val = x;
                o->s[b]->cnt = o->s[b]->sz = 1;
//                Update(o);
                Splay(o->s[b],NULL);
                return;
            }
        }
        o = o->s[b];
    }
}
inline void Find(int val){
    Node *o = tree;
    for(; o != NULL; o = o->s[val >= o->val]) if(o->val == val) break;
    if(o != NULL) Splay(o,NULL);
}
inline int Rnk(int x){
    Find(x);
    return Size(tree->s[0]) + 1;
}
inline int Kth(int k){
    Node* o = tree;
    for(;;){
        if(Size(o->s[0])+o->cnt >= k && Size(o->s[0]) < k) return o->val;
        else if(Size(o->s[0]) >= k) o = o->s[0];
        else{
            k -= (Size(o->s[0]) + o->cnt);
            o = o->s[1];
        }
    }
}
inline void Delete(int val){
    Find(val);
    if(tree->val != val) return;
    if(tree->cnt > 1){
        --tree->cnt;
        return;
    }
    else if(tree->s[0] == NULL){
        tree = tree->s[1];
        if(tree != NULL) tree->fa = NULL;
    }
    else if(tree->s[1] == NULL){
        tree = tree->s[0];
        if(tree != NULL) tree->fa = NULL;
    }
    else{
        Node* l_max = tree->s[0];
        for(; l_max->s[1] != NULL; l_max = l_max->s[1]);
        Splay(l_max,tree);
        Node* pre_tree = tree;
        tree = l_max;
        tree->fa = NULL;
        tree->s[1] = pre_tree->s[1];
        if(pre_tree->s[1] != NULL) pre_tree->s[1]->fa = tree;
    }
}
inline int Pre(int val){
    Insert(val);
    Node* o = tree->s[0];
    for(; o->s[1] != NULL; o = o->s[1]);
    Delete(val);
    return o->val;
}
inline int Nxt(int val){
    Insert(val);
    Node* o = tree->s[1];
    for(; o->s[0] != NULL; o = o->s[0]);
    Delete(val);
    return o->val;
}
int main(){
    read(n);
    while(n--){
        read(opt),read(x);
        if(opt == 1) Insert(x);
        if(opt == 2) Delete(x);
        if(opt == 3) printf("%d
", Rnk(x));
        if(opt == 4) printf("%d
", Kth(x));
        if(opt == 5) printf("%d
", Pre(x));
        if(opt == 6) printf("%d
", Nxt(x));
    }
    return 0;
}

 

以上是关于「Splay」指针版与数组版模板的主要内容,如果未能解决你的问题,请参考以下文章

[模板]洛谷T3369 普通平衡树 链表&递归版无父指针版Splay

史上最详尽的平衡树(splay)讲解与模板(非指针版spaly)

Splay指针模板

字典树模板( 指针版 && 数组版 )

在洛谷3369 Treap模板题 中发现的Splay详解

codevs 4244 平衡树练习