splay模板

一个模板splay


①申明:

int key[120000],f[120000],v[120000],size[120000],ch[120000][2],sz,root;
// key[i]--节点i所表示的数字 f[i]--i的父节点 size[i]--i节点的子树大小(包括i) 
// v[i]--key[i]出现的次数 ch[i][0]--i的左儿子 ch[i][1]--i的右儿子 sz整棵树大小 root整棵树的根


②各个操作

void clear(int x) //清理 

{
  key[x]=f[x]=v[x]=size[x]=ch[x][0]=ch[x][1]=0;


int  get(int x)//求x是f[x]的左儿子还是右儿子 
{
   return ch[f[x]][1]==x;


void updata(int x)//操作导致修改后要更新 
{
   if (x)
   {
    size[x]=v[x];
    size[x]+=size[ch[x][0]];
    size[x]+=size[ch[x][1]];
   }
}

void rotate(int x)//将x旋转成他父节点的父节点 
{
  int fa=f[x]; int gf=f[fa]; int which=get(x); 
  ch[fa][which]=ch[x][which^1]; f[ch[fa][which]]=fa;//如果他是父节点的左儿子,则转后父节点无左儿子,他无右儿子,所以他右儿子接上父节点,反之亦然
  f[fa]=x;ch[x][which^1]=fa; f[x]=gf;
  if (gf) ch[gf][ch[gf][1]==fa]=x;
  updata(fa); updata(x);
}


void splay(int x)//将x旋转至根 
{
  for (int fa;(fa=f[x]);rotate(x))
   if (f[fa])
   {
    int a=get(fa); int b=get(x);
    if (a==b) rotate(fa);else rotate(x);//如果父节点,祖父节点,和x一线了,先转父节点
   }
  root=x; 



void insert(int x)//插入 
{
   int now=root; int fa=0;
   if (root==0) {sz++;ch[sz][1]=ch[sz][0]=0;f[sz]=0;key[sz]=x;v[sz]=1;size[sz]=1;root=sz;return;}
   while(1)
   {
    if (key[now]==x){v[now]++;updata(now);updata(fa);splay(now);break;}
    fa=now;
    now=ch[now][key[now]<x];
    if (now==0)
    {
      sz++;
      ch[sz][0]=ch[sz][1]=0; v[sz]=1; key[sz]=x; size[sz]=1; f[sz]=fa;
      ch[fa][key[fa]<x]=sz;
      updata(fa);
      splay(sz);
      break;
    }
   }
}


int  find(int x)// 求x的排名 
{
  int ans=0; int now=root;
  while(1)
  {
  if (x<key[now])
   now=ch[now][0];
  else
  {
   ans+=size[ch[now][0]];
   if (x==key[now]){splay(now);return ans+1;}
   ans+=v[now];
   now=ch[now][1];
  }
  }
}


int findx(int x)//求排名为x的数 
{
   int now=root;
   while(1)
   {
    if (ch[now][0]&& x<=size[ch[now][0]])
     now=ch[now][0];
    else 
    {
    int temp=size[ch[now][0]]+v[now];
    if (x<=temp) return key[now];
    x-=temp; now=ch[now][1];
    }
   }
}


int pre()//求根的左子树的最大的数
{
  int now=ch[root][0];
  while(ch[now][1]) now=ch[now][1];
  return now;
}


int next()//求根的右子树的最小的数 
{
  int now =ch[root][1];
  while(ch[now][0]) now=ch[now][0];
  return now;
}


void del(int x)//删除x 
{
  int haha=find(x);
  if (v[root]>1) {v[root]--;return;}
  if (!ch[root][1]&&!ch[root][0]) {clear(root);root=0;return ;}
  if (!ch[root][1]) {int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;}
  if (!ch[root][0]) {int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;}
  int lb=pre(),oldroot=root;
  splay(lb); 
  f[ch[oldroot][1]]=root;
  f[root]=0;
  ch[root][1]=ch[oldroot][1];
  clear(oldroot);
  updata(root);
  return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值