• [知识学习] Splay


    背景

    最近在学平衡树,学了一下Splay,自己打了一些注释,现在放到这里


    Luogu链接

    题目

    3224: Tyvj 1728 普通平衡树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 26996  Solved: 12493
    [Submit][Status][Discuss]

    Description

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    Input

    第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

    Output

    对于操作3,4,5,6每行输出一个数,表示对应答案

    Sample Input

    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598

    Sample Output

    106465
    84185
    492737

    HINT

    1.n的数据范围:n<=100000

    2.每个数的数据范围:[-2e9,2e9]


    代码

    贴一份便于自己理解的Splay代码(蒯代码可耻)

    #include <bits/stdc++.h>
    #define N (100000+5)
    using namespace std;
    int fa[N],ch[N][2],val[N],cnt[N],siz[N],rt,tot;
    void maintain(int x){//改变节点位置后,更新size
    	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];//左+右+自身大小
    }
    bool get(int x){//判断x是fa[x]的左儿子(0),还是右儿子(1)
    	return x==ch[fa[x]][1];
    }
    void clear(int x){//销毁节点x
    	ch[x][0]=ch[x][1]=fa[x]=val[x]=siz[x]=cnt[x]=0;
    }
    void rotate(int x){
    	int y=fa[x],z=fa[y],k=get(x);//y:x的父亲,z:x的爷爷,k:x是y的哪个儿子
    	ch[y][k]=ch[x][k^1];//y的那个儿子设置成x的另一个儿子
    	fa[ch[x][k^1]]=y;//和上语句是一组
    	ch[x][k^1]=y;//x的另一个儿子设置成y
    	fa[y]=x;//和上语句是一组
    	fa[x]=z;//x的父亲设为z
    	if(z) ch[z][y==ch[z][1]]=x;//y原来的那个位置设为x
    	maintain(y),maintain(x);//更新节点大小
    }
    void splay(int x,int g=0){//Splay操作
    	while(fa[x]!=g){//如果父亲不是目标节点,就旋转
    		int f=fa[x],ff=fa[f];//父亲,祖父
    		if(ff!=g) get(x)==get(f)?rotate(f):rotate(x);//如果在同一边,则转父亲,不在同一边,转自己
    		rotate(x);//再转一次自己
    	}
    	if(!g)rt=x;
    }
    void insert(int k){//插入操作
    	if(!rt){//如果没有根节点
    		val[++tot]=k;//tot++,tot的val为k
    		cnt[tot]++;//tot的cnt++
    		rt=tot;//根节点是tot
    		maintain(rt);//更新rt
    		return;
    	}//不然的话
    	int cnr=rt,f=0;//设当前节点(cnr)为rt,当前节点的父亲(f)为0
    	while(1){
    		if(val[cnr]==k){//如果当前节点的值正好是k
    			cnt[cnr]++;//当前节点cnt++
    			maintain(cnr);//更新cnr
    			maintain(f);//更新其father(f)
    			splay(cnr);//Splay一下
    			break;//结束
    		}
    		//跳到下一个节点
    		f=cnr;//父亲变成当前的这个
    		cnr=ch[cnr][val[cnr]<k];//当前的这个变成其儿子
    		if(!cnr){//如果当前节点是空的话
    			val[++tot]=k;//tot++,val为k
    			cnt[tot]++;//cnt++
    			fa[tot]=f;//father为f
    			ch[f][val[f]<k]=tot;//father的这个儿子为tot
    			maintain(tot);//更新tot
    			maintain(f);//更新f
    			splay(tot);//Splay一下
    			break;//结束
    		}
    	}
    }
    /*Splay基本功能****************************************************/
    int rk(int k){//查询x的排名
    	int res=0,cnr=rt;//res为排名,cnr当前节点
    	while(1){
    		if(k<val[cnr]){//在树左边
    			cnr=ch[cnr][0];//当前节点为左儿子
    		}
    		else{//在树右边或自己
    			res+=siz[ch[cnr][0]];//加左子树的所有siz
    			if(k==val[cnr]){//正好是自己
    				splay(cnr);
    				return res+1;//返回res+1
    			}
    			res+=cnt[cnr];//不是自己,加上cnt
    			cnr=ch[cnr][1];//向右边查询
    		}
    	}
    }
    int kth(int k){//查询k大的数(k为剩余排名)
    	int cnr=rt;//初始节点为根
    	while(1){
    		if(ch[cnr][0]&&k<=siz[ch[cnr][0]]) cnr=ch[cnr][0];
    		//左子树有值且k比左子树大小要小(或等) 当前节点跳至左子树
    		else{
    			k-=cnt[cnr]+siz[ch[cnr][0]];//k-左子树大小
    			if(k<=0) return val[cnr];//k<=0 该节点为所求
    			cnr=ch[cnr][1];//跳至右儿子
    		}
    	}
    }
    int pre(){//查询前驱
    	int cnr=ch[rt][0];
    	while(ch[cnr][1]) cnr=ch[cnr][1];
    	return cnr;
    }
    int nxt(){//查询后继
    	int cnr=ch[rt][1];
    	while(ch[cnr][0]) cnr=ch[cnr][0];
    	return cnr;
    }
    int del(int k){//删除操作
    	rk(k);
    	if(cnt[rt]>1){
    		cnr[rt]--;
    		maintain(rt);
    		return;
    	}
    	if(!ch[rt][0]&&!ch[rt][1]){
    		clear(rt);
    		rt=0;
    		return;
    	}
    	if(!ch[rt][0]){
    		int cnr=rt;
    		rt=ch[rt][1];
    		fa[rt]=0;
    		clear(cnr);
    		return;
    	}
    	if(!ch[rt][1]){
    		int cnr=rt;
    		rt=ch[rt][1];
    		fa[rt]=0;
    		clear(cnr);
    		return;
    	}
    	int x=pre(),cnr=rt;
    	splay(x);
    	fa[ch[cnr][1]]=x;
    	ch[x][1]=ch[cnr][1];
    	clear(cnr);
    	maintain(rt);
    }
    int main(){
    	
    	return 0;
    }
    
    
    转载请注明出处--Xx_queue
  • 相关阅读:
    BeautifulSoup
    requests
    安装xpath helper
    取消搜狗输入法的快捷键
    numpy初识 old
    Jupyter Notebook 快捷键
    安装numpy、matplotlib
    JavaScript 继承 -JavaScript高级程序设计
    mac /windows
    unicode 地址
  • 原文地址:https://www.cnblogs.com/Xx-queue/p/12191814.html
Copyright © 2020-2023  润新知