

struct Tree{ //定义一个结构体来存树 
    int L,R; //L表示当前节点的左子节点,R表示当前节点的右子节点 
    int size; //size表示以当前节点为根节点的子树大小 
}Treap[99];
inline void upt (int x){   //更新以x为根节点的子树大小 
    Treap[x].size=Treap[Treap[x].L].size+Treap[Treap[x].R].size+1;
    return;
}
inline void Zig (int &x){ //右旋以x为根节点的子树
						  //用取地址符方便直接修改新的根节点 
    int z=Treap[x].L;   //用z存储x的左子节点 
    Treap[x].L=Treap[z].R; //更新x左子节点为x左子节点的右子节点 
    Treap[z].R=x; //x原左子节点的右子节点更新为x 
    Treap[z].size=Treap[x].size; //维护子树大小 
    upt (x);
    x=z; //当前子树根节点更新为z 
    return; //返回这颗新子树的根节点 
}
inline void Zag (int &x){ //左旋以x为根节点的子树 
						  //用取地址符方便直接修改新的根节点 
    int z=Treap[x].R;   //用z存储x的右子节点 
    Treap[x].R=Treap[z].L; //更新x右子节点为x右子节点的左子节点 
    Treap[z].L=x; //x原右子节点的左子节点更新为x 
    Treap[z].size=Treap[x].size; //维护子树大小 
    upt (x);
    x=z; //当前子树根节点更新为z 
    return; //返回这颗新子树的根节点 
}

             2-10           
             /  \           
	    /    \          
	   /      \         
	 1-23    4-18       
	         /  \       
	        /    \      
	       /      \     
	    3-20     7-34   
	       \            
	        \           
	         \          
	          5         
画风突然简陋
             2-10           
             /  \           
	    /    \          
	   /      \         
	 1-23    4-18       
	         /  \       
	        /    \      
	       /      \     
	    3-20     7-34   
	       \            
	        \           
	         \          
 	        5-11        
             2-10           
             /  \           
	    /    \          
	   /      \         
	 1-23    4-18       
	         /  \       
	        /    \      
	       /      \     
	    5-11     7-34   
	       \            
	        \           
	         \          
 	        3-20        
             2-10           
             /  \           
	    /    \          
	   /      \         
	 1-23    5-11       
	         /  \       
	        /    \      
	       /      \     
	    3-20     4-18  
	               \            
	                \           
	                 \          
 	                7-34  
struct Tree{ //定义一个结构体来存树 
    int L,R; //L表示当前节点的左子节点,R表示当前节点的右子节点 
    int size; //size表示以当前节点为根节点的子树大小 
    int v; //v为当前节点的权值 
    int r; //r表示随机的优先级 
}Treap[99];
inline void insert (int &x,int k){ //当前节点为x,插入一个权值为k的点
								   //用取地址符方便直接修改原值 
    if (!x){ //当前位置没有节点,即已经找到位置了 
        x=++Tot; //新建一个节点
        Treap[x].v=k; //新节点的权值为k
        Treap[x].r=rand (); //赋予一个随机的优先级
        Treap[x].size=1; //以新节点为根节点的子树大小为1
        return; 
    }
    else ++Treap[x].size; //如果当前位置存在节点,那么新节点
	 					  //肯定在当前节点的左右子节点中 
	 					  //所以直接将当前节点的子树大小加一
    if (k<=Treap[x].v){ //如果k比当前节点权值小 
        insert (Treap[x].L,k);//向当前节点的左子节点继续搜索
        if (Treap[x].r>Treap[Treap[x].L].r) //当优先级不满足小根堆时
            Zig (x);  	                    //右旋当前节点 
    }
    else {                     //如果k比当前节点权值大 
        insert (Treap[x].R,k); //向当前节点的右子节点继续搜索
        if (Treap[x].r>Treap[Treap[x].R].r) //当优先级不满足小根堆时
            Zag (x);  	                    //左旋当前节点 
    } 
    return;
}
         2-10           
         /  \           
        /    \          
       /      \         
     1-23    5-11       
             /  \       
            /    \      
           /      \     
        3-20     4-18  
                    \            
                     \           
                      \          
                     7-34 
         2-10           
         /  \           
        /    \          
       /      \         
     1-23    5-11       
             /  \       
            /    \      
           /      \     
        3-20     4-18   
         2-10           
         /  \           
        /    \          
       /      \         
     1-23    5-11       
             /  \       
            /    \      
           /      \     
        3-20     7-34 
         2-10           
         /  \           
        /    \          
       /      \         
     1-23    4-18      
             /  \       
            /    \      
           /      \     
        5-11     7-34  
         /
        / 
       /  
    3-20
         2-10           
         /  \           
        /    \          
       /      \         
     1-23    4-18      
             /  \       
            /    \      
           /      \     
        3-20     7-34  
struct Tree{ //定义一个结构体来存树 
    int L,R; //L表示当前节点的左子节点,R表示当前节点的右子节点 
    int size; //size表示以当前节点为根节点的子树大小 
    int v; //v为当前节点的权值 
    int r; //r表示随机的优先级 
}Treap[99];
inline void Delete (int &x,int k){ //x为当前节点位置 k为需要删除的权值的节点 
								   //用取地址符方便修改x父节点的子节点 
    if (Treap[x].v==k){ //找到需要删除的节点了 
        if (!Treap[x].L||!Treap[x].R) x=Treap[x].L+Treap[x].R; //第一种情况可以一起处理
															   //以为若该节点无子节点,x就会等于0
															   //若只有一个子节点,x就会变为他的存在的那个子节点 
        else if (Treap[Treap[x].L].r<Treap[Treap[x].R].r){ //当前节点左子节点的优先级比较小的情况
            Zig (x); //右旋当前节点
            Delete (x,k); //因为x被旋下去了所以继续向下找直到可以删除x这个节点 
        }
        else { //当前节点左子节点的优先级比较大的情况
            Zag (x); //左旋当前节点
            Delete (x,k); //因为x被旋下去了所以继续向下找直到可以删除x这个节点 
        }
        return;
    }
    Treap[x].size--; //维护子树大小,因为需要删除的节点一定在当前节点的子节点上
    if (k<=Treap[x].v) //如果k比当前节点权值小 
        Delete (Treap[x].L,K); //向左寻找要删除节点 
    else                      //如果k比当前节点权值大 
        Delete (Treap[x].R,K); //向右寻找要删除节点
    return; 
}     
inline int rank (int k){ //查询权值为k的排名 
    int ans=0,x=root; //ans为比k小的节点数 root为构造的Treap的根节点
    while (x){ //当x不为0时即还可以找到节点 
        if (k==Treap[x].v) //找到节点了
            return  ans+Treap[Treap[x].L].size+1; //返回当前节点右子节点的子树大小加上
												  //之前比查询权值大的节点数加一
        else if (k<Treap[x].v) //如果k比当前节点权值小
            x=Treap[x].L;      //向当前节点的左子节点进行查找,
						       //因为当前节点比查询权值大的话无法对答案做出任何贡献
        else { //如果k比当前节点权值大
            ans+=Treap[Treap[x].L].size+1; //比k小的节点数就增加了
			                               //当前节点(1)和其左子树大小(Treap[Treap[x].L].size)
            x=Treap[x].R //继续向左寻找 
        } 
    }
    return 0; //如果不存在这个节点返回0(不一定为0,按照自己需求进行修改) 
}
inline int rank (int k){ //查询排名为k的节点权值大小 
    int x=root; //root为构造的Treap的根节点
    while (x){ //当x不为0时即还可以找到节点 
        if (k==Treap[Treap[x].L].size) //找到节点了
            return  Treap[x].v;       //返回当前节点的权值 
        else if (k<=Treap[Treap[x].L].size) //如果k的排名比当前节点右子树大小小
            x=Treap[x].L;      				//向当前节点的左子节点进行查找,
        else { //如果k的排名比当前节点右子树大小大
            k-=(Treap[Treap[x].L].size+1) //k要减去当前节点左子树大小+1 
            x=Treap[x].R //继续向左寻找 
        } 
    }
    return 0; //如果不存在这个节点返回0(不一定为0,按照自己需求进行修改) 
}
     
inline int QueryPre (int k){ //查询前驱 
    int x=root,ans=-2147483647;  //x为根节点,ans为答案,初始化为极小值是为了防止没有找到前驱 
    while (x){  //循环至空的节点 
        if (Treap[x].v<=k){ //如果当前节点比k小 
            ans=Treap[x].v; //更新答案 
            x=Treap[x].R;  //继续向左查找 
        }
    else x=Treap[x].L; //如果当前节点比k大则不更新
						   //向左查找直到找到权值比k小的节点再更新 
    }
    return ans; //返回答案 
}
inline int QuerySuf (int k){ //查询后继,同上 
    int x=root,ans=2147483647;
    while (x){
        if (Treap[x].v>=k){
            ans=Treap[x].v;
            x=Treap[x].L;
        }
        else x=Treap[x].R;
    }
    return ans;
}
              5
            /               /                /                 3           7
      /   \	  /        /     \ 	 /         /       \	/          1         4 6         9
             5                       7
            /  \                                 /    \                                /      \                              3         6                     9
      /   \	    
     /     \ 
    /          1        4 
struct node{   //用结构体存树 
   int L,R;   //L,R分别为当前节点的左/右节点编号 
   int k;     //k为当前节点权值 
   int r;     //r为随机的优先级 
   int size;  //size当前节点的子树大小 
}treap[2020022];
inline void del (int x){  //调整子树大小 
   treap[x].size=treap[treap[x].R].size+treap[treap[x].L].size+1;
   return;
}
inline void Split (int v,int k,int &L,int &R){  //v表示当前节点,k为分裂权值 
   											//L表示可以添加到左树的位置 
   											//R表示可以添加到右树的位置 
   											//用取地址符来直接修改节点 
   if (!v){     //当当前节点为空节点时,左右树的可添加节点也变为空节点 
       L=R=0;
       return;
   }
   if (treap[v].k<=k){                    //当当前节点权值小于等于分裂权值k时 
       L=v;                               //将当前节点放到左树上可添加节点的位置 
       Split (treap[v].R,k,treap[v].R,R); //同时继续向右分裂,R不变 
   									   //但是左树可以更新的节点变为了当前节点的右子节点 
   									   //因为当前节点和其左子树都到了左树
   									   //所以当前节点的右子节点空了出来= = 
       del (v);  //调整子树大小,这个和Treap的函数是一样
       return;
   }
   else if (treap[v].k>k){                //当当前节点权值大于分裂权值k时 
       R=v;                               //将当前节点放到右树上可添加节点的位置 
       Split (treap[v].L,k,L,treap[v].L); //同时继续向左分裂,L不变
   									   //但是右树可以更新的节点变为了当前节点的左子节点 
   									   //理由同上 		 
       del (v); //调整子树大小 
       return;
   }
}
Spilt (root,k,l,r); //按权值k将根节点为root的树分为两棵树 
   				//左边树的根节点为l,右边树的根节点为r 
   									  
struct node{   //用结构体存树 
   int L,R;   //L,R分别为当前节点的左/右节点编号 
   int k;     //k为当前节点权值 
   int r;     //r为随机的优先级 
   int size;  //size当前节点的子树大小 
}treap[2020022];
inline int merge (int TA,int TB){  //合并根节点为TA和根节点为TB的树 
   if (!TA||!TB) return TA+TB;    //当其中至少一个为空节点时返回那个非空节点
   							   //若都为空节点直接返回空节点 
   if (treap[TA].r<treap[TB].r){           //比较根节点优先级大小,如果TA的优先级小时 
       treap[TA].R=merge (treap[TA].R,TB); //根节点为TA的右子节点更新为
   										//合并其右子树和根节点为TB的树 后的根节点 
       del (TA);     //调整子树大小 
       return TA;
   }
   else{                                   //若TA优先级较大时 
       treap[TB].L=merge (TA,treap[TB].L); //根节点为TB的左子节点更新为
   										//合并根节点为TA的树和其左子树 后的根节点 
       del (TB);     //调整子树大小 
       return TB;
   }
}
             5
           /             /              /              3         7
     /   \       /       /     \     /        /       \   /         1       4 6         9
             5                           9
           /   \ 
          /              /       \                
       3           7
     /   \       /       
    /     \     /        
   /       \   /           
  1        4 6            
             5                           9      8
           /   \ 
          /              /       \                
       3           7
     /   \       /       
    /     \     /        
   /       \   /           
  1         4 6            
              5                           9     
            /   \ 
           /               /       \                
        3           7
      /   \       /   \    
     /     \     /     \   
    /       \   /       \    
   1        4 6         8   
              5                              
            /   \ 
           /               /       \                
        3           7
      /   \       /   \    
     /     \     /     \   
    /       \   /       \    
   1        4 6         8  
   						  \		
   						      						       						     9
struct node{   //用结构体存树 
    int L,R;   //L,R分别为当前节点的左/右节点编号 
    int k;     //k为当前节点权值 
    int r;     //r为随机的优先级 
    int size;  //size当前节点的子树大小 
}treap[2020022];
int root,l,r,Treap_size;       //root为整棵平衡树的根节点编号
							   //l,r分别为分裂后的左右树根节点编号
							   //Treap_size为节点数 
inline void newnode (int x){     //新建一个节点,节点数加一 
    treap[++Treap_size].size=1;  //其子树大小为一 
    treap[Treap_size].k=x;       //权值为插入节点权值 
    treap[Treap_size].r=rand();  //赋予随机的优先级 
    return;
}
inline void Insert (int x){     //插入权值为x的点 
    split (root,x,l,r);         //按权值x分裂整棵树 
    newnode (x);                //新建权值为x的节点 
    root=merge (l,Treap_size);  //合并左树和新节点 
    root=merge (root,r);        //合并上面合并后的树和右树 
    return;
}			
             5                              
           /   \ 
          /              /       \                
       3          7
     /   \       /   \    
    /     \     /     \   
   /       \   /       \    
  1        4 6         8  
  						  \		
  						     						      						     9
              5                       8       
            /   \                                 /     \                                /       \                              3           7                     9
      /   \       /      
     /     \     /        
    /       \   /           
   1         4 6           
              5           7            8       
            /   \                                  /     \                                 /       \                               3          6                       9
      /   \           
     /     \           
    /       \            
   1        4           
        
inline void Delete (int x){  //删除权值为x的节点 
    int TC=0;                //TC存三树的根节点 
    Split (root,x,l,r);      //先按权值x分裂整棵树为一二树
							 //l为一树根节点编号,r为二树根节点编号 
    Split (l,x-1,l,TC);      //然后按权值x-1分裂一树为一三树
							 //l为新的一树的根节点编号,TC为三树的根节点编号 
    TC=merge (treap[TC].L,treap[TC].R); //然后先将TC的左右子树合并,将TC节点删除 
    root=merge (l,TC);       //合并一三树 
    root=merge (root,r);     //合并剩下的两棵树 
    return;
}
inline int getrank (int k){   //查询权值为k的元素的排名 
    Split (root,k-1,l,r);     //按权值为k-1分裂为两棵子树,那么左树的节点权值必定小于k 
    int res=treap[l].size+1;  //答案就是左树的大小加一	
    root=merge (l,r);         //不要忘记合并 
    return res;
}
inline int Kth (int v,int k){           //几乎一模一样的代码,我也不多做注释了 
										//只是注意v的意思是在以v为根节点的树中进行查找 
    while (v){
        if (k<=treap[treap[v].L].size)
            v=treap[v].L;
        else if (k==treap[treap[v].L].size+1)
            return treap[v].k;
        else {
            k-=(treap[treap[v].L].size+1);
            v=treap[v].R;
        } 
    }
    return 0;
}
inline int QueryPre (int k){ //查询前驱 
    Split (root,k-1,l,r); 
    int res=Kth (l,treap[l].size);
    root=merge (l,r);
    return treap[res].k; //返回答案 
}
inline int QuerySuf (int k){ //查询后继,同上 
    Split (root,k,l,r); 
    int res=Kth (r,1);
    root=merge (l,r);
    return treap[res].k; //返回答案 
}
原文:https://www.cnblogs.com/IQZ-HUCSr-TOE/p/12630998.html