「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\n", qxz.Rank(x));
        if(opt == 4) printf("%d\n", qxz.Kth(x));
        if(opt == 5) printf("%d\n", qxz.Pre(x));
        if(opt == 6) printf("%d\n", 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\n", Rnk(x));
        if(opt == 4) printf("%d\n", Kth(x));
        if(opt == 5) printf("%d\n", Pre(x));
        if(opt == 6) printf("%d\n", Nxt(x));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/qixingzhi/p/9365586.html

时间: 2024-10-08 17:00:49

「Splay」指针版与数组版模板的相关文章

[LuoguP3808] 【模板】AC自动机(简单版)数组版

待填坑 Code #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=1000000+1000; struct AC_AutoMation { #define root 0 static const int sigma_size=26; struct node { int nxt[sigma_size],s

Linux 小知识翻译 - 「Linux」和「发行版」之间的关系

「Linux」本来指的仅仅是内核.5年之前大多都是这么认为的,但是最近不这么说了. 最近一般都说「Linux」是个 OS,这里的OS,不仅仅是内核,而是指电脑的整体环境(除了内核,还包括一些外围的软件). 内核本来是作为硬件和各种应用软件之间的桥梁而存在的,只有内核的PC是无法使用的. 因此,会将各式各样的软件和内核组合在一起,作为一个可以运行的OS来打包,打包后的OS就被称为「Linux发行版」. 最近,把「Linux发行版」称为「Linux」的情况也比较多了. 但是,「Linux内核」只有一

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

模板 : #include<string.h> #include<stdio.h> #include<malloc.h> #include<iostream> #include<algorithm> using namespace std; const int maxn = 26; struct Trie { Trie *Next[maxn]; int v; inline void init(){ this->v = 1; for(int

「C」 数组、字符串、指针

一.数组 (一)数组 概念:用来存储一组数据的构造数据类型 特点:只能存放一种类型的数据,如全部是int型或者全部是char型,数组里的数据成为元素. (二)数组的定义 格式: 类型 数组名[元素个数]: 举例:存储5个人的年龄 int agrs[5];  // 在内存中开辟4x5=20个字节的存储空间 可以在定义数组的同时对数组进行初始化: int ages[5] = {17,18,19,20,21}: 遍历数组: for(int i = 0;i<5;i++) { printf(“ages[%

HDU 4287 Intelligent IME(字典树数组版)

Intelligent IME Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4776    Accepted Submission(s): 2227 Problem Description We all use cell phone today. And we must be familiar with the intelligen

CF #261 div2 D. Pashmak and Parmida&amp;#39;s problem (树状数组版)

Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partner to be clever too (although he's not)! Parmida has prepared the following test problem for Pashmak. There is a sequence a that consists of n

数据结构实践——猴子选大王(数组版)

本文针对数据结构基础系列网络课程(5): 数组与广义表的实践项目. [项目 - 猴子选大王(数组版)] 一群猴子,编号是1,2,3 -m,这群猴子(m个)按照1-m的顺序围坐一圈.从第1只开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,最后一只出圈的猴子为大王.输入m和n,输出猴子离开圈子的顺序,从中也可以看出最后为大王是几号猴子. 要求采用数组作为存储结构完成. [参考解答1] 在一个数组中,数组中用1表示猴子在圈中,用0表示猴子已经出圈,数组下标对应与猴子编号对应(例如数组元素p[0

求逆序对 (树状数组版)

基本思想和线段树求解逆序数是一样的,前一篇<求逆序对 线段树版>也介绍过,先对输入数组离散,数组里的元素都不相同可以直接hash,存在相同的数话可以采用二分. 离散化后对于每个f[i],找到f[i]+1~ n中的个数,也就是到i这个位置,一共有多少比f[i]大的数,统计之后在将f[i]的位置上的数量加1. 这样一来统计的就是类似a[i]~n的和,可以想象成 把树状数组反过来统计,即统计的时候加lowbit,更新的时候减lowbit. 还是 以POJ 2299为例. #include <i

「ZJOI2017」树状数组

「ZJOI2017」树状数组 以下均基于模2意义下,默认\(n,m\)同阶. 熟悉树状数组的应该可以发现,这题其实是求\(l-1\)和\(r\)位置值相同的概率. 显然\(l=1\)的情况需要特盘. 大暴力 对于\(l=1\)的情况,可以发现一个操作不会产生影响当且仅当增加\(r\)的值,而其他情况会改变\(l-1\)或\(r\). 对于\(l!=1\)的情况: ? 针对一次修改区间\([ql,qr]\). \([ql,qr]\)包含\(l-1,r\),那么有\(\displaystyle 2