Magic splay tree

Magic splay tree

to sum up

  1. splay tree is a BST, which maintains the balance of the splay tree through continuous operation; basic idea is that the frequency of the high points (each point is actually looking for) is rotated by the operation of the roots splay
  2. Core operations:
  • update (x): maintenance of information, similar to the tree line in push_up
  • rotate (x): single screw, i.e. to the position x y of the parent node, note the order (y Alternatively, the subtree of x y is added, most subtree of x y)
  • splay (int x, int s): The x node is rotated to below s. Case 1: x, y, z co-linear, to rotate (y), then rotate (x); case 2: not collinear, rotate (x) twice
  • find (int x): after rotation required to find the root
  • insert (int x): count ++ found, otherwise a new node and initialize
  • Next (int x, int f): Looking predecessor and successor
  • Delete (int x): predecessor and successor to go first, and then the precursor of rotation to the root root, following subsequent rotation to the root, and then delete x (at this time t [nxt] .ch [0])
  • kth (int x): Comparison of size can

  • tarjan engage algorithms are hard to write, and it is easy to mistake Yeah, not a good debugging it
  • reference: blog1 blog2 blog3

## template title luogu3369

Code ###

#include <bits/stdc++.h>
using namespace std;
const int N=201000;
struct splay_tree
{
   int ff,cnt,ch[2],val,size;
} t[N];
int root,tot;//root==0 表示是空树 根节点的ff为0
void update(int x)//更新节点x
{
   t[x].size = t[t[x].ch[0]].size+t[t[x].ch[1]].size+t[x].cnt;
   
}
void rotate(int x)//对x进行单旋
{
   int y = t[x].ff; int z =t[y].ff;
   int k = (t[y].ch[1]==x);
   t[z].ch[t[z].ch[1]==y] = x;// 用x替换z节点的儿子节点y
   t[x].ff = z;
   t[y].ch[k] = t[x].ch[1^k];  //先把 x的子树移到y
   t[t[x].ch[1^k]].ff = y;
   t[x].ch[1^k] = y; //y-x 与 x-y关系相反,构建x-y关系
   t[y].ff = x;
   update(y);update(x);// 先更新下面的层
   
}
void splay(int x,int s)//将x 旋转到 s下方, s==0 则是旋转到根
{
   while(t[x].ff!=s)
   {
       int y=t[x].ff,z=t[y].ff;
       if (z!=s)//z==s 意味只需旋转一下x即可
           (t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);//如果 x,z,y同线,先旋转y,再旋转x;否则旋转两次x
       rotate(x);
   }
   if (s==0) //s==0 x旋转到根,更新root
       root=x;
}
void find(int x)
{
   int u=root;
   if (!u)
       return ;//空树
   while(t[u].ch[x>t[u].val] && x!=t[u].val)//x>t[u].val 向右找, x< t[u].val 向左找
       u=t[u].ch[x>t[u].val];
   //也有可能找不到
   splay(u,0);//找到x,将其splay到根
}
void insert(int x) //插入操作
{
   int u=root,ff=0;
   while(u && t[u].val!=x)
   {
       ff=u;
       u=t[u].ch[x>t[u].val];
   }
   if (u)//找到元素x的节点,计数++
       t[u].cnt++;
   else//没有找到则产生新节点
   {
       u=++tot;
       if (ff)//ff!=0 u不是根节点
           t[ff].ch[x>t[ff].val]=u;
       t[u].ch[0]=t[u].ch[1]=0;//初始化t[u]
       t[tot].ff=ff;
       t[tot].val=x;
       t[tot].cnt=1;
       t[tot].size=1;
   }
   splay(u,0);//u splay到根节点
}
int Next(int x,int f)//f=0 表示前驱 f=1表示后继
{
   find(x);// 如果找到x所在节点 会被splay到根节点
   int u=root;
   if (t[u].val>x && f) //find没有找到x
       return u;
   if (t[u].val<x && !f)
       return u;
   //find 找打了x,且此时再根节点上
   u=t[u].ch[f];
   while(t[u].ch[f^1])//左子树的最右边节点/右子树的最左边节点
       u=t[u].ch[f^1];
   return u;
}
void Delete(int x)
{
   int last=Next(x,0);
   int Net=Next(x,1);
   splay(last,0);
   splay(Net,last);  //找到前驱和后继并将前驱splay到根节点,后继splay到根节点下面; 则x代表的节点在是根节点的左儿子
   int del=t[Net].ch[0];
   if (t[del].cnt>1)//计数--
   {
       t[del].cnt--;
       splay(del,0);
   }
   else
       t[Net].ch[0]=0;//彻底删掉
}
int kth(int x)
{
   int u=root;
   while(t[u].size<x)//不存在排名为x
       return 0;
   while(1)
   {
       int y=t[u].ch[0];
       if (x>t[y].size+t[u].cnt) //在右子树
       {
           x-=t[y].size+t[u].cnt;
           u=t[u].ch[1];
       }
       else if (t[y].size>=x)//在左子树
           u=y;
       else //就在u
           return t[u].val;
   }
}

/*
插入数值x。
删除数值x(若有多个相同的数,应只删除一个)。
查询数值x的排名(若有多个相同的数,应输出最小的排名)。
查询排名为x的数值。
求数值x的前驱(前驱定义为小于x的最大的数)。
求数值x的后继(后继定义为大于x的最小的数)。
*/
int main()
{
   int n;
   scanf("%d",&n);
   insert(1e9); //始终保持能够找到前驱和后继
   insert(-1e9);
   while(n--)
   {
       int opt,x;
       scanf("%d%d",&opt,&x);
       if (opt==1)
           insert(x);
       if (opt==2)
           Delete(x);
       if (opt==3)
       {
           find(x);
           printf("%d\n",t[t[root].ch[0]].size);
       }
       if (opt==4)
           printf("%d\n",kth(x+1));
       if (opt==5)
           printf("%d\n",t[Next(x,0)].val);
       if (opt==6)
           printf("%d\n",t[Next(x,1)].val);
   }
   return 0;
}

Guess you like

Origin www.cnblogs.com/fridayfang/p/11086692.html