• 普通伸展树(带注释版)


    这个涵盖了一般的基本操作~欢迎指错喔!

    [因为一直觉得有点不安全 害怕Orz]

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 101000
    int root;
    
    struct trnode
    {
        int d,n,c,f,son[2];//d为值,f为父亲的编号,c为控制的节点个数,n为同值的节点个数
    }tr[maxn];int len;
    
    void update(int x)//更新x所控制的节点数 
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        tr[x].c= tr[lc].c + tr[rc].c + tr[x].n;
    }
    
    void add(int d,int f)//添加值为d的点,认f为父亲,同时,f也认它为孩子
    {
        len++;
        tr[len].d=d; tr[len].n=1;  tr[len].c=1;
        tr[len].son[0]=tr[len].son[1]=0;
        tr[len].f=f; if( d<tr[f].d) tr[f].son[0]=len; else tr[f].son[1]=len; 
    }
    
    void rotate(int x)//左旋(w=0)或者右旋(w=1)
    {
        int y= tr[x].f,z=tr[y].f,w,r,R;//x在旋转之前,要确定x的父亲y和爷爷z
        if(tr[y].son[0]==x)w=1;else w=0;//下来建立关系 
        
        r=tr[x].son[w];      R=y;//x的儿子 ->准备当新儿子  (r表示儿子,R表示父亲)
        tr[R].son[1-w]=r ;
        if(r!=0) tr[r].f=R;
        
        r=x;                 R=z;//x ->准备当新儿子
        if( tr[R].son[0]==y ) tr[R].son[0]=r;else  tr[R].son[1]=r;
        tr[r].f=R;
    
        r=y;                 R=x; //x的父亲 ->准备当新儿子
        tr[R].son[w]=r;
        tr[r].f=R;
        
        update(y); // 先更新处于下层的点
        update(x); // 再更新上层的x
    }
    
    void splay(int x,int rt)// 该函数功能是为了让x成为rt的孩子(左或右都行)
    {
        while(tr[x].f!=rt) // 如果rt是x的父亲,则什么都不用做,否则x就要不断向上旋转 
        {
        	int y=tr[x].f,z=tr[y].f; // 准备x的父亲和爷爷
            if( z==rt)  rotate(x);//如果 x的爷爷是rt,那么x只需要旋转一次(相当于跳一层)
            else//否则一次跳两层 
            {
            	if( (tr[z].son[0]==y ) == ( tr[y].son[0]==x)  ){ rotate(y); rotate(x);} 
    		else                                           { rotate(x); rotate(x);}
            }
        }
        if(rt==0) root=x;
    }
    int findip(int d)   //找值为d的节点的地址,如果不存在d,有可能是接近d的(或大或小)
    {
        int x=root;
        while(tr[x].d!=d)
        {
            if(d<tr[x].d)
            {
                if( tr[x].son[0]!=0 )x=tr[x].son[0];else break;
            }
            else // if( tr[x].d<d)
            {
                if( tr[x].son[1]!=0 )x=tr[x].son[1];else break;
            }
        }
        return x;
    }
    
    void ins(int d)//插入数值为d的一个节点
    {
        if(root==0) { add(d,0); root=len; return ; }
        
        int x=findip(d);
        if( tr[x].d==d) tr[x].n++;
        else            add(d,x);//自洽:算法自身能包容它自己的“缺点” 
        update(x); 
        splay(x,0);
    }
    
    void del(int d)   // 删除数值为d的一个节点
    {
        int x=findip(d);splay(x,0);  //找人,并且让y 当树根
        
        if( tr[x].n>1) { tr[x].n--;tr[x].c--;  return;}   // 多重身份,就不用删点
    
        if(tr[x].son[0]==0 && tr[x].son[1]==0){ root=0; len=0; }     // 四种情况
        else if(tr[x].son[0]==0 && tr[x].son[1]!=0) {root=tr[x].son[1]; tr[root].f=0;}
        else if(tr[x].son[0]!=0 && tr[x].son[1]==0) {root=tr[x].son[0]; tr[root].f=0;}
        else //if( tr[x].son[0]!= 0&& tr[x].son[1]!=0)
        {
            int p=tr[x].son[0];
    	while( tr[p].son[1]!=0) p=tr[p].son[1];
    		
    	splay(p,x);
            root=p; tr[root].f=0;
    		
            int r=tr[x].son[1],R=p;
            tr[R].son[1]=r ;
            tr[r].f= R;
        
            update(R);
        }
    }
    int findpaiming(int d)//找排名 
    {
        int x=findip(d);splay(x,0);
        return tr[tr[x].son[0]].c+1;
    }
    
    int  findshuzi(int k)  // 找排名为k的值
    {
        int x=root;
        while(1)
        {
            int lc=tr[x].son[0],rc=tr[x].son[1];
            if( k<=tr[lc].c ) x=lc; //去左孩子找
            else if( k>tr[lc].c+ tr[x].n ) { k-=tr[lc].c+ tr[x].n;  x=rc;} //去右孩子找
            else break;  //就是你
        }
        splay(x,0);
        return tr[x].d;
    }
    int findqianqu(int d) //找前驱
    {
        int x= findip(d);splay(x,0);
        if( d<=tr[x].d && tr[x].son[0]!=0 )//如果是if( d<tr[x].d && tr[x].son[0]!=0 )则找到的是:小于等于d的前驱 
        {
            x=tr[x].son[0];
            while( tr[x].son[1]!=0) x= tr[x].son[1];
        }
        if( tr[x].d >=d) x=0;//如果是if( tr[x].d>d)则找到的是:小于等于d的前驱
        return x;
    }
    
    int findhouji(int d)  //找后继
    {
        int x= findip(d);splay(x,0);
        if( tr[x].d<=d && tr[x].son[1]!=0 )
        {
            x=tr[x].son[1];
            while( tr[x].son[0]!=0) x= tr[x].son[0];
        }
        if( tr[x].d <=d) x=0;
        return x;
    }
    
    int main()
    {
        //freopen("ptszs.in","r",stdin);
        //freopen("ptszs.out","w",stdout);
        int n;scanf("%d",&n);
        root=0;len=0;
        for(int i=1;i<=n;i++)
        {
            int cz,x;scanf("%d%d",&cz,&x);
                 if(cz==1) ins(x);
            else if(cz==2) del(x);
            else if(cz==3) printf("%d
    ",findpaiming(x) );
            else if(cz==4) printf("%d
    ",findshuzi(x) );
            else if(cz==5) printf("%d
    ",tr[findqianqu(x)].d);
            else if(cz==6) printf("%d
    ",tr[findhouji(x)].d);
        }
        return 0;
    }
    


  • 相关阅读:
    python入坑级
    nginx配置文件详解
    nginx看端口使用情况
    linux安装nginx
    linux安装jdk1.7
    linux设置tomcat开机启动
    redis master配置了密码进行主从同步
    linux搭建mysql 5.6.28
    linux搭建redis数据库
    找出一组数里出现频率最高的3个数(1.3)
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527882.html
Copyright © 2020-2023  润新知