• [模板]洛谷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 }
  • 相关阅读:
    Javascript高级编程学习笔记(66)—— 事件(10)变动事件
    Javascript高级编程学习笔记(65)—— 事件(9)复合事件
    Javascript高级编程学习笔记(64)—— 事件(8)键盘与文本事件
    Javascript高级编程学习笔记(63)—— 事件(7)鼠标及滚轮事件
    Javascript高级编程学习笔记(62)—— 事件(6)焦点事件
    Javascript高级编程学习笔记(61)—— 事件(5)UI事件
    Javascript高级编程学习笔记(60)—— 事件(4)事件类型
    Javascript高级编程学习笔记(59)—— 事件(3)事件对象
    Javascript高级编程学习笔记(58)—— 事件(2)事件处理程序
    Javascript高级编程学习笔记(57)—— 事件(1)事件流
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/7222118.html
Copyright © 2020-2023  润新知