首页 > 其他分享 >Splay树【模板】

Splay树【模板】

时间:2023-04-15 11:01:55浏览次数:31  
标签:splay val get int tr Splay 节点 模板

Splay树模板

P3369 [模板]普通平衡树

#include<bits/stdc++.h>
using namespace std;
#define ls(x) tr[x].s[0]
#define rs(x) tr[x].s[1]

const int maxn=1e5+10;
//node
struct node{
  int s[2],val,cnt,siz,fa;
  //左右儿子,value,出现的次数,子树大小,父节点编号 
  void init(int p,int v){
  	fa=p;val=v;
  	cnt=siz=1;
  }
}tr[maxn];
int root,idx=0;//根节点编号,总的节点数量
 
//pushup更新每个节点的size 
void pushup(int x){
  tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+tr[x].cnt;
  //siz是该节点子树的节点数量,不要忘记+cnt 
} 
//rotate旋转 
void rotate(int x){
  int y=tr[x].fa,z=tr[y].fa;
  int k= rs(y)==x;
  tr[y].s[k]=tr[x].s[k^1];
  tr[tr[x].s[k^1]].fa=y;//更新y->b
  tr[x].s[k^1]=y;
  tr[y].fa=x;//更新边x->y
  tr[z].s[rs(z)==y]=x;
  tr[x].fa=z;//更新边z->x
  pushup(y);pushup(x);//顺序必须是先更新y再更新x,因为y是x的儿子 
}
//splay把x旋转到k节点下面
void splay(int x,int k){
  while(tr[x].fa!=k){//只要上一位不是k就一直执行 
   int y=tr[x].fa,z=tr[y].fa;
    if(z!=k) //折转底,直转中 
  	  (rs(y)==x)^(rs(z)==y)
		?rotate(x):rotate(y); 
    rotate(x); 	
  } 
  if(k==0) root=x;//标记根节点 
} 
//find查找val并把它转到根节点
void find(int val){
  int x=root;
  while(tr[x].s[val>tr[x].val]&&val!=tr[x].val)
  	x=tr[x].s[val>tr[x].val];
  splay(x,0);
}
//get_pre得到val的前驱
//返回的是节点的标号 
int get_pre(int val){
  find(val);
  int x=root;
  if(val>tr[x].val) return x;
  x=ls(x);
  while(tr[x].s[1]) x=rs(x);
  return x;
}
//get_suc得到val的后继
//返回节点编号而不是值 
int get_suc(int val){
  find(val);
  int x=root;
  if(val<tr[x].val) return x;
  x=rs(x);
  while(tr[x].s[0]) x=ls(x);
  return x; 
} 
//update插入数字val
void update(int val){
  int x=root,p=0;
  while(x&&val!=tr[x].val)//只要是这一个点有值就行,不用判断儿子有值 
    p=x,x=tr[x].s[val>tr[x].val];
  if(!x){
  	x=++idx;
  	tr[p].s[val>tr[p].val]=x;//在父节点上加一个儿子 
  	tr[x].init(p,val);
  }
  else tr[x].cnt++;
  splay(x,0);//更新整棵树 
}
//get_rank找到val的排名
int get_rank(int val){
  find(val);
  return tr[tr[root].s[0]].siz;
}
//find_rank找到排名为k的数 
int find_rank(int k){
  int x=root;
  while(1){
  	if(tr[tr[x].s[0]].siz+tr[x].cnt<k){
  	  k-=(tr[tr[x].s[0]].siz+tr[x].cnt);	
  	  x=rs(x);//这个时候x已经改变了,所以k应该在前面就减了 
	}
  	else{
  	  if(tr[tr[x].s[0]].siz>=k) x=ls(x);
	  else break;	
	}
  }
  splay(x,0);
  return tr[x].val;
}
//del删除数字val
void del(int val){
  int y=get_pre(val),z=get_suc(val);
  splay(y,0),splay(z,y);
  int x=tr[z].s[0];
  if(tr[x].cnt>1) tr[x].cnt--,splay(x,0);
  else tr[z].s[0]=0,splay(z,0);
} 

int main(){
  /*2023.4.15 hewanying P3369 [模板]普通平衡树 Splay树*/ 
  int n;
  update(-1e9);update(1e9);//哨兵 
  scanf("%d",&n);
  int opt=0,x;
  while(n--){
  	scanf("%d%d",&opt,&x);
  	if(opt==1) update(x);
  	if(opt==2) del(x);
  	if(opt==3) printf("%d\n",get_rank(x));
  	if(opt==4) printf("%d\n",find_rank(x+1));
  	if(opt==5) printf("%d\n",tr[get_pre(x)].val);
  	if(opt==6) printf("%d\n",tr[get_suc(x)].val); 
  }
  return 0;
}
每一次rotate

有顺时针旋转和逆时针旋转两种情况
image

每一次splay

折转底,直转中
在一次旋转后,这棵二叉查找树就变得矮胖了

splay作用

1.把想要的节点转到根节点
2.更新整棵树,所以每一次修改过后都要splay一次

时间复杂度

\(O(m\log_{2}{n})\)

标签:splay,val,get,int,tr,Splay,节点,模板
From: https://www.cnblogs.com/hewanying0622/p/17320686.html

相关文章

  • 平衡树模板——splay
    /*在splay中0不能算作是根节点,只能说是一个标记点如果谁的父亲是0,那么谁就是根节点*/#include<bits/stdc++.h>usingnamespacestd;constintM=1e5+5;constintinf=1e9;#definettr#definesizesizintcnt=0,root=0;structsplay{intch[2],siz,cnt,va......
  • 模板元编程与函数式
    参考:【公开课】现代C++进阶:模板元编程与函数式ppt和代码在高性能计算中,一般使用函数式和元编程,而不使用面向对象。简单的介绍:类型自动推导模板参数、模板特化简单的实例:#include<iostream>template<classT>Ttwice(Tt){returnt*2;}std::stringtwice(std::......
  • vue2源码-五、将模板编译解析成AST语法树1
    将模板编译成ast语法树complileToFunction方法vue数据渲染:template模板->ast语法树->render函数,模板编译的最终结果结果就是render函数。在complileToFunction方法中,生成render函数,需要以下两个核心步骤:通过parserHTML方法:将模板(template或html)内容编译成ast语法树通过co......
  • ipconfig /displaydns ipconfig /flushdns
    ipconfig/displaydns显示系统中已经缓存的DNS域名ipconfig/flushdns这是清除DNS缓存用的。当访问一个网站时系统将从DNS缓存中读取该域名所对应的IP地址,当查找不到时就会到系统中查找hosts文件,如果还没有那么才会向DNS服务器请求一个DNS查询,DNS服务器将返回该域名所对应的IP,在......
  • 算法基础模板整理(动态规划篇)
    背包问题01背包问题static const int N = 1010;int dp[N][N], v[N], w[N], n, c;int main(){    cin >> n >> c;    for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];    for(int i = 1; i <= n; i ++ )    ......
  • 算法基础模板整理(基础图论篇)
    拓扑排序bool topo(){    queue<int> q;    for(int u = 1; u <= n; u ++ )        if(!ind[u]) q.push(u);        int cnt = 0;    while(!q.empty()){        int u = q.front();        q.pop(); ......
  • 算法基础模板整理(高阶数据结构篇)
    树状数组动态区间和询问+点修改int lowbit(int x){    return x & -x;}void add(int x, int v){    for(int i = x; i <= n; i += lowbit(i)) tree[i] += v;}int query(int x){    int res = 0;    for(int i = x; i......
  • VMWare Horizon Linux 手动场 cannot open display 错误
    环境:系统:rhel7.9horizonagent版本:2209桌面:Gnome问题描述:防火墙已关闭的情况下,在使用LSF交互式任务时不能打开带界面的程序(xhost+已经事先执行过)。解决问题:vim/usr/lib/vmware/viewagent/bin/StartXServer.sh找到xdmcp_opt="-query127.0.0.1-once"改为xdmcp_opt......
  • 【D02】Bootstrap免费精选模板推荐,附上Django中使用模板教程
    前端模板-AnchorUIKIT前言今天介绍一款制作精良、开源、免费的Bootstrap模板——AnchorUIKIT该模板使用的是Bootstrapv4版本本文将介绍如何在Django中导入该模板的静态资源包并使用介绍官方文档Anchor-afreeBootstrapUIKit(bootcss.com)预览官方文档......
  • CAD模板怎么设置?CAD模板设置技巧
    在CAD制图过程中,如果需要设置一个模板的话该如何操作呢?CAD模板怎么设置?本节CAD制图教程就和小编一起来了解一下浩辰CAD软件中设置CAD模板的相关操作技巧吧!CAD模板设置步骤:步骤一:启动浩辰CAD后,打开或者是新建一个可以作为模板的图形文件。步骤二:点击软件左上角的【G】图标,在下拉......