首页 > 代码库 > [模板]洛谷T3391 文艺平衡树 链表&递归版、无父指针版Splay

[模板]洛谷T3391 文艺平衡树 链表&递归版、无父指针版Splay

指针大法好

无父指针Splay大法好

大佬们的“改变旋转方向”萌新表示不懂,于是就自己乱搞出了下面的搞法。。。

代码如下,萌新写的丑,诸位大佬见谅QwQ~

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<ctime>
  5 #include<cstdlib>
  6 #include<ctime>
  7 
  8 #include<string>
  9 #include<stack>
 10 #include<queue>
 11 #include<vector>
 12 #include<algorithm>
 13 #include<map>
 14 
 15 using namespace std;
 16 
 17 struct node{
 18     int key;  //结点键值 
 19     int size;  //以本结点为根的子树的结点数量 
 20     bool lazy;  //懒标记,记录对以本结点为根的子树的操作,0表示不旋转,1表示待旋转 
 21     node *ch[2];  //左右子树指针 
 22     
 23     void maintain(){  //维护结点信息(size) 
 24         size=1;
 25         if(ch[0]!=NULL)size+=ch[0]->size;
 26         if(ch[1]!=NULL)size+=ch[1]->size;
 27     }
 28     
 29     int cmp(int x){  //求在以本结点为根的子树中,排名为x的节点相对于本节点的位置 
 30         int s=0;
 31         if(ch[0]!=NULL)s=ch[0]->size;
 32         
 33         if(x<=s)return 0;  //在左子树 
 34         else if(x==s+1)return -1;  //本结点即为所求 
 35         else return 1;  //在右子树 
 36     }
 37 };
 38 
 39 void pushdown(node *);  //懒标记下放 
 40 void rotate(node* &,bool);  //旋转 
 41 void splay(node* &,int);  //按照排名伸展 
 42 void insert(node *&,int);  //没有自带伸展 
 43 void travel(node *);  //遍历 
 44 
 45 node *root=NULL;  //根节点指针 
 46 
 47 int n,m,i;
 48 int l,r;
 49 int r_x;  //待伸展的总排名为r+1的节点在根节点的右子树中的排名
 50 
 51 int main(){
 52     scanf("%d%d",&n,&m);
 53     
 54     for(i=1;i<=n;i++){
 55         insert(root,i);
 56         splay(root,i);
 57     }  //插入并伸展 
 58     
 59     for(i=1;i<=m;i++){
 60         scanf("%d%d",&l,&r);
 61         
 62         if(l>1 && r<n){  //一般情况 
 63             splay(root,l-1);
 64             
 65             r_x=r;
 66             if(root->ch[0]!=NULL)r_x-=root->ch[0]->size;  //计算r_x 
 67             
 68             splay(root->ch[1],r_x);  //已将待翻转区间提取至root->ch[1]->ch[0] 
 69             
 70             root->ch[1]->ch[0]->lazy^=1;  //打标记 
 71         }
 72         
 73         else if(l==1 && r==n)root->lazy^=1;  //若待翻转区间为整个序列,则只需将根节点打上标记即可 
 74         
 75         else{
 76             if(l==1){
 77                 splay(root,r+1);
 78                 root->ch[0]->lazy^=1;
 79             }  //若待翻转区间为[1,r],且r<n,则将结点r+1伸展至根节点,则根节点的左子树即为待翻转区间 
 80             else{
 81                 splay(root,l-1);
 82                 root->ch[1]->lazy^=1;
 83             }  //同理 
 84         }    
 85     }
 86     
 87     travel(root);  //遍历整棵树 
 88     
 89     return 0;
 90 }
 91 
 92 void pushdown(node *p){
 93     swap(p->ch[0],p->ch[1]);  //交换左右子树 
 94     
 95     if(p->ch[0]!=NULL)p->ch[0]->lazy^=1;
 96     if(p->ch[1]!=NULL)p->ch[1]->lazy^=1;  //下放到左右子树 
 97     
 98     p->lazy=0;  //清空本节点的懒标记 
 99 }
100 
101 void rotate(node* &p,bool f){
102     if(p->lazy)pushdown(p);  //下放顺序:自上而下 
103     
104     node *t=p->ch[f^1];
105     
106     if(t->lazy)pushdown(t);
107     
108     p->ch[f^1]=t->ch[f];
109     t->ch[f]=p;
110     
111     p->maintain();  //维护顺序:自底向上 
112     t->maintain();
113     
114     p=t;
115 }
116 
117 void splay(node* &p,int x){
118     if(p->lazy)pushdown(p);  //由于要操作p的子树,故需下放,下面同理 
119     
120     int d1=p->cmp(x);  //d1:待伸展节点相对于p的位置 
121     
122     if(d1==-1 || p->ch[d1]==NULL)return;  //若当前节点即为待伸展节点,或d1指向的子树为空,则直接返回 
123     
124     if(p->ch[d1]->lazy)pushdown(p->ch[d1]);
125     
126     int x2;
127     if(d1==0)x2=x;
128     else{
129         if(p->ch[0]==NULL)x2=x-1;
130         else x2=x-p->ch[0]->size-1;
131     }  //x2:待伸展节点在d1指向的子树中的排名 
132     
133     int d2=p->ch[d1]->cmp(x2);  //d2:待伸展节点相对于d1指向的节点的位置 
134     
135     if(d2==-1 || p->ch[d1]->ch[d2]==NULL){
136         rotate(p,d1^1);
137         return;
138     }  //若d1指向的节点即为待伸展节点,或d2指向的子树为空,则直接将d1指向的节点上旋,然后返回即可 
139     else{
140         int x3;  //在此处,由于splay函数在开始执行时会pushdown,故不需在此处pushdown 
141         if(d2==0)x3=x2;
142         else{
143             if(p->ch[d1]->ch[0]==NULL)x3=x2-1;
144             else x3=x2-p->ch[d1]->ch[0]->size-1;
145         }  //x3:待伸展节点在d2指向的子树中的排名 
146         
147         splay(p->ch[d1]->ch[d2],x3);  //将待伸展节点递归伸展至d2指向的点 
148         
149         if(d1==d2){  //一字型旋转 
150             rotate(p,d1^1); 
151             rotate(p,d2^1);
152         }
153         else{  //之字形旋转 
154             rotate(p->ch[d1],d1);  //d2^1==d1
155             rotate(p,d2);  //d1^1==d2
156         }
157     }
158 }
159 
160 void insert(node* &p,int x){
161     if(p==NULL){
162         p=(node *)malloc(sizeof(node));
163         p->key=x;
164         p->size=1;
165         p->lazy=0;
166         p->ch[0]=p->ch[1]=NULL;
167         return;
168     }  //新建节点 
169     else{
170         if(p->lazy)pushdown(p);  //由于要操作p的子树,故需下放 
171         insert(p->ch[1],x);  //由于按左右顺序排名,故需插入至最右端 
172         p->size++;  //维护本节点信息 
173     }
174 }
175 
176 void travel(node *p){
177     if(p->lazy)pushdown(p);  //先进行下放,于是可以得到正确的顺序,然后遍历即可 
178     
179     if(p->ch[0]!=NULL)travel(p->ch[0]);  //递归遍历左子树 
180     
181     printf("%d ",p->key);  //遍历本节点 
182     
183     if(p->ch[1]!=NULL)travel(p->ch[1]);  //递归遍历右子树 
184 }

 

[模板]洛谷T3391 文艺平衡树 链表&递归版、无父指针版Splay