普通平衡树[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]的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3224Tyvj 1728 普通平衡树 平衡树的三种姿势 :splay,Treap,ScapeGoat_Tree