[Data]Splay-二叉排序树

emm接下来讲讲splay,个人比较喜欢splay,其主要操作就是伸展旋转,它的应用比较广泛,对于一个有序序列,它可以实现区间翻转,还可以求区间第k大。

 

splay的核心操作-旋转(本人的旋转可能与一般旋转有点不一样):

通过上图两种旋转我们可以发现一点点规律:若要rotate(x),先获取x为该父亲的右或左节点p,p为1或0,那么x的(p^1)子节点的父亲指向x的父亲,x的父亲的(p)子节点指向

x的(p^1)子节点,x的父亲只想原有父亲的祖先,同时更新祖先儿子,更新子树大小;我们可以通过循环来使x节点伸展到根;

 1 bool get(int x){
 2     return x==p[p[x].f].son[1];
 3 }
 4 void rorate(int x){
 5     int f=p[x].f,ff=p[p[x].f].f,opt=get(x);
 6     p[f].son[opt]=p[x].son[opt^1];
 7     p[p[x].son[opt^1]].f=f;
 8     if(ff) p[ff].son[get(f)]=x;
 9     else root=x;
10 
11     p[x].f=ff;
12     p[f].f=x;
13         p[x].son[opt^1]=f;
14     //    printf("%d %d\n",f,x);
15     refresh(f);
16     refresh(x);
17 }
View Code

其他的话个人觉得应该没什么好讲的了,删除和插入操作都基本和普通平衡树一样。学会splay后可以去刷下luogu的模板题splay,以下为我的代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 #define maxn 100010
  5 struct node{
  6     int size,son[2],f,rev;
  7 }p[maxn];
  8 int root,n,m;
  9 bool get(int x){
 10     return x==p[p[x].f].son[1];
 11 }
 12 void refresh(int x){
 13     if(x){
 14         int size=1;
 15         if(p[x].son[0]) size+=p[p[x].son[0]].size;
 16         if(p[x].son[1]) size+=p[p[x].son[1]].size;
 17         p[x].size=size;
 18     }
 19 }
 20 void build(int l,int r,int f){
 21     if(l>r) return;
 22     int mid=(l+r)/2;
 23     if(f>mid) p[f].son[0]=mid;
 24     else p[f].son[1]=mid;
 25     if(f!=mid) p[mid].f=f;
 26     p[mid].size=1;
 27     if(l==r) return;
 28     build(l,mid-1,mid);
 29     build(mid+1,r,mid);
 30     refresh(mid);
 31 }
 32 void rorate(int x){
 33     int f=p[x].f,ff=p[p[x].f].f,opt=get(x);
 34     p[f].son[opt]=p[x].son[opt^1];
 35     p[p[x].son[opt^1]].f=f;
 36     if(ff) p[ff].son[get(f)]=x;
 37     else root=x;
 38 
 39     p[x].f=ff;
 40     p[f].f=x;
 41         p[x].son[opt^1]=f;
 42     //    printf("%d %d\n",f,x);
 43     refresh(f);
 44     refresh(x);
 45 }
 46 void rever(int x){
 47     swap(p[x].son[0],p[x].son[1]);
 48     p[p[x].son[0]].rev^=1;
 49     p[p[x].son[1]].rev^=1;
 50     p[x].rev^=1;
 51     //printf("%d %d\n",p[x].son[0],p[x].son[1]);
 52 }
 53 void splay(int x,bool k){
 54     if(!k){
 55         while(p[x].f){
 56             rorate(x);
 57             root=x;
 58         }
 59         root=x;
 60     }
 61     else{
 62         while(p[p[x].f].f){
 63             rorate(x);
 64         }
 65         p[root].son[1]=x;
 66     }
 67 }
 68 int find(int x){
 69     int now=root;
 70     while(1){
 71         //  printf("%d %d\n",x,now);
 72         if(p[now].rev) rever(now);
 73         if(p[p[now].son[0]].size>=x){
 74             now=p[now].son[0];
 75         }
 76         else{
 77             if(p[p[now].son[0]].size==x-1) return now;
 78             x-=p[p[now].son[0]].size+1;
 79             now=p[now].son[1];
 80         }
 81     }
 82 }
 83 void dfout(int x){
 84     if(p[x].rev) rever(x);
 85     if(p[x].son[0]) dfout(p[x].son[0]);
 86     if(x>1&&x<n+2) printf("%d ",x-1);
 87     if(p[x].son[1]) dfout(p[x].son[1]);
 88 }
 89 int main()
 90 {
 91     int l,r;
 92     scanf("%d %d",&n,&m);
 93     root=(n+3)/2;
 94     build(1,n+2,root);
 95     while(m--){
 96         scanf("%d %d",&l,&r);
 97         if(l==r) continue;
 98         l=find(l);
 99         r=find(r+2);
100         splay(l,0);
101         splay(r,1);
102         p[p[p[root].son[1]].son[0]].rev^=1;
103     }
104     dfout(root);
105     return 0;
106 }
View Code

 

posted @ 2018-01-01 15:57  Konnyaku  阅读(242)  评论(0编辑  收藏  举报