2019.1.22注释:
DEl操作中,虽然实现了删除节点的操作,但是删除节点后的splay树十分难看
所以正常操作是先splay前驱到根,然后splay后继到根的左(右)子,
然后删除根的左(右)子的要删除的叶节点。
如要搞清楚为什么这么做能减少时间,需要清楚splay期望的计算方法
#include<iostream>
#include<cstdio>
#define MAXN 100000
#define INF 0x7ffffff
using namespace std;
int n;
int ch[MAXN][2],use[MAXN],fa[MAXN];
int size=0,root=0;
inline void rotate(int x,int &k)
{
int y=fa[x],z=fa[y],d;
if(ch[y][0]==x)d=0;else d=1;
if(y==k)k=x;
else
{
if(ch[z][0]==y)ch[z][0]=x;
else ch[z][1]=x;
}
fa[y]=x,fa[x]=z,fa[ch[x][d^1]]=y;
ch[y][d]=ch[x][d^1],ch[x][d^1]=y;
}
void splay(int x,int &k)
{
int y,z;
while(x!=k)
{
y=fa[x],z=fa[y];
if(y!=k)
{
if((ch[y][0]==x)^(ch[z][0]==y))rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
void insert(int &x,int num,int pre)
{
if(x==0){x=++size,use[x]=num,fa[x]=pre,splay(x,root);return ;}
if(num<use[x])insert(ch[x][0],num,x);
else insert(ch[x][1],num,x);
}
int find(int x,int num)
{
if(use[x]==num)return x;
if(num<use[x])return find(ch[x][0],num);
else return find(ch[x][1],num);
}
void del(int x)
{
splay(x,root);
if(ch[x][0]*ch[x][1]==0)root=ch[x][0]+ch[x][1];
else
{
int t=ch[x][1];
while(ch[t][0]!=0)t=ch[t][0];
fa[ch[x][0]]=t;ch[t][0]=ch[x][0];
root=ch[x][1];
}
fa[root]=0;
}
void print(int x)
{
if(x==0)return ;
print(ch[x][0]);
printf("%d ",use[x]);
print(ch[x][1]);
}
int main()
{
scanf("%d",&n);
int t1,t2;
for(int i=1;i<=n;i++)
{
scanf("%d",&t1);
insert(root,t1,0);
}
print(root);
while(cin>>t1)
{
t2=find(root,t1);
printf("%d\n",t2);
if(t2)del(t2);
print(root);
}
while(1);
return 0;
}