普通平衡树[splay]

Posted Candy?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了普通平衡树[splay]相关的知识,希望对你有一定的参考价值。

参考:

http://blog.csdn.net/clove_unique/article/details/50630280

gty课件

找一个好的风格太难了,自己习惯用struct,就强行用struct写了一下数组版的,同时加了些宏简化代码

都是迭代写法

splay要维护fa指向父亲

rotate是把x转到fa,要更新f和x

splay是把x转到tar的孩子,x成为root就是tar=0,注意更新root

ins考虑空树,考虑已经存在,插入新节点的话要保留last到最后处理父亲,更新父亲(其实就是更新了这棵树,由于splay没必要更新祖先)然后做splay

(递归写法的传引用已经解决了设置祖先的问题)

del

先找要删除的,splay到根

1.多个直接--

2.空树直接root=0

3.只有一个儿子,令独生子变成根,删去该点。
4.左右儿子都有。找到左子树中权值最大的点,将其 splay 到左儿子的位置。然后将 整棵右子树挂在左儿子的右边。删除节点。 

其他操作差不多了

 

ps:比treap慢了一倍

 

//
//  main.cpp
//  splay
//
//  Created by Candy on 27/11/2016.
//  Copyright © 2016 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}
struct node{
    int fa,ch[2],v,w,size;
}t[N];
int cnt,root;
inline int wh(int x){return t[pa].ch[1]==x;}
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline void rotate(int x){//x-->pa
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(g) t[g].ch[wh(f)]=x;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    t[x].fa=g;
    update(f);update(x);
}
inline void splay(int x,int tar){//x-->x.fa==tar
    for(;t[x].fa!=tar;rotate(x))
        if(t[pa].fa!=tar) rotate(wh(x)==wh(pa)?pa:x);
    if(tar==0) root=x;
}

inline int nw(int v){
    cnt++;
    t[cnt].v=v;t[cnt].ch[0]=t[cnt].ch[1]=t[cnt].fa=0;
    t[cnt].w=t[cnt].size=1;
    return cnt;
}
inline void ins(int v){
    if(root==0){root=nw(v);return;}//empty tree
    int x=root,last=0;
    while(x!=0){
        if(t[x].v==v){t[x].w++;t[x].size++;splay(x,0);return;}
        last=x;
        if(v<t[x].v) x=lc; else x=rc;
    }
    int tmp=nw(v);
    if(v<t[last].v) t[last].ch[0]=tmp;
    else t[last].ch[1]=tmp;
    t[tmp].fa=last;update(last);//no need for ancient because splay()
    splay(tmp,0);
}
inline int find(int v){
    int x=root;
    while(x!=0){
        if(v==t[x].v) break;
        if(v<t[x].v) x=lc;
        else x=rc;
    }
    if(x!=0) splay(x,0);
    return x;
}
inline int pre(){
    int x=t[root].ch[0];
    while(rc) x=rc;
    return x;
}
inline void del(int v){
    int x=find(v);
    if(t[x].w>1) {t[x].w--,t[x].size--;return;}
    if(lc==0&&rc==0) root=0;
    else if(rc==0) t[lc].fa=0,root=lc;
    else if(lc==0) t[rc].fa=0,root=rc;
    else{
        int tmp=t[root].ch[0];
        while(t[tmp].ch[1]) tmp=t[tmp].ch[1];
        splay(tmp,x);
        t[tmp].ch[1]=rc;t[rc].fa=tmp;
        t[tmp].fa=0;
        root=tmp;
        update(root);
    }
}
inline int rnk(int v){
    int x=root,ls=0;
    while(x!=0){
        if(t[x].v==v){
            int ans=ls+t[lc].size+1;
            splay(x,0);
            return ans;
        }
        if(v<t[x].v) x=lc;
        else ls+=t[lc].size+t[x].w,x=rc;
    }
    return -1;
}
inline int kth(int k){
    int x=root,ls=0;
    while(x!=0){
        int tmp=ls+t[lc].size;
        if(tmp+1<=k&&k<=tmp+t[x].w){
            splay(x,0);return t[x].v;
        }
        if(k<=tmp) x=lc;
        else ls=tmp+t[x].w,x=rc;
    }
    return -1;
}
inline int pre(int v){
    int ans=0,x=root;
    while(x!=0){
        if(t[x].v<v) ans=x,x=rc;
        else x=lc;
    }
    return ans;
}
inline int suf(int v){
    int ans=0,x=root;
    while(x!=0){//printf("suf %d %d\n",x,t[x].v);
        if(v<t[x].v) ans=x,x=lc;
        else x=rc;
    }
    return ans;
}
int n,op,x,ans;
int main(int argc, const char * argv[]){
    n=read();
    while(n--){
        op=read();x=read();
        switch(op){
            case 1:ins(x);break;
            case 2:del(x);break;
            case 3:printf("%d\n",rnk(x));break;
            case 4:printf("%d\n",kth(x));break;
            case 5:ans=pre(x);printf("%d\n",t[ans].v);break;
            case 6:ans=suf(x);printf("%d\n",t[ans].v);break;
        }
    }
    return 0;
}

 

以上是关于普通平衡树[splay]的主要内容,如果未能解决你的问题,请参考以下文章

普通平衡树[splay]

洛谷P3369普通平衡树(splay)

bzoj3224Tyvj 1728 普通平衡树 平衡树的三种姿势 :splay,Treap,ScapeGoat_Tree

BZOJ 3224 普通平衡树 平衡树的两种姿势:SBT,splay

3224. 普通平衡树平衡树-splay

bzoj3224 普通平衡树 splay模板