Splay模板
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1.插入 x数 2.删除 x数(若有多个相同的数,因只删除一个) 3.查询 x数的排名(排名定义为比当前数小的数的个数 +1。若有多个相同的数,因输出最小的排名) 4.查询排名为 x的数 5.求 x的前驱(前驱定义为小于 x,且最大的数) 6.求 x的后继(后继定义为大于 x ,且最小的数) 输入输出格式 输入格式: 第一行为 n ,表示操作的个数,下面 n行每行有两个数opt 和 x , opt 表示操作的序号( 1≤opt≤6 ) 输出格式: 对于操作 3,4,5,6每行输出一个数,表示对应答案 输入输出样例 输入样例#1: 10 1 106465 4 1 1 317721 1 460929 1 644985 1 84185 1 89851 6 81968 1 492737 5 493598 输出样例1# 106465 84185 492737 说明 时空限制:1000ms,128M 1.n的数据范围:n≤100000 2.每个数的数据范围: [-10^7,10^7] 来源:Tyvj1728 原名:普通平衡树
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define MAX 500100 int root=0,N,tot=0; inline int read() { register int x=0,t=1; register char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-'){t=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} return x*t; } struct Node { int ch[2];//子节点 int ff;//父节点 int cnt;//数量 int val;//值 int son;//儿子数量 }t[MAX]; void push_up(int u)//计算儿子数 { t[u].son=t[t[u].ch[0]].son+t[t[u].ch[1]].son+t[u].cnt; } void rotate(int x)//旋转 { register int y=t[x].ff; register int z=t[y].ff; register int k=t[y].ch[1]==x;//x是y的左或右儿子 t[z].ch[t[z].ch[1]==y]=x; t[x].ff=z; t[y].ch[k]=t[x].ch[k^1]; t[t[x].ch[k^1]].ff=y; t[x].ch[k^1]=y; t[y].ff=x; push_up(y);push_up(x); } void Splay(int x,int goal)//把x节点旋转到目标位置 { while(t[x].ff!=goal) { int y=t[x].ff; int z=t[y].ff; if(z!=goal)//旋转 (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y); rotate(x); } if(goal==0) root=x;//当前的根节点 } void insert(int x)//插入x { int u=root,ff=0; while(u&&t[u].val!=x) { ff=u; u=t[u].ch[x>t[u].val]; } if(u)//已经有这个数字了 t[u].cnt++;//计算数字个数 else//不存在这个数字,加入新的节点 { u=++tot;//总的节点数 if(ff) t[ff].ch[x>t[ff].val]=u; t[tot].ch[0]=0; t[tot].ch[1]=0; t[tot].ff=ff; t[tot].val=x; t[tot].cnt=1; t[tot].son=1; } Splay(u,0); } void Find(int x)//查找x的位置 { int u=root; if(!u)return;//不存在节点,无法查找排名 while(t[u].ch[x>t[u].val]&&x!=t[u].val)//找到x所在的位置 u=t[u].ch[x>t[u].val]; Splay(u,0); } int Next(int x,int f)//查找前驱/后继 { Find(x);//查找x的位置(Splay操作到根节点) int u=root; if((t[u].val>x&&f)||(t[u].val<x&&!f))return u;//返回结果 u=t[u].ch[f]; while(t[u].ch[f^1])u=t[u].ch[f^1]; return u; } void Delete(int x)//删除x { int last=Next(x,0);//查找前驱 int next=Next(x,1);//查找后继 Splay(last,0);Splay(next,last); int del=t[next].ch[0]; if(t[del].cnt>1) { t[del].cnt--;//存在多个这个数字,直接减去一个 Splay(del,0); } else t[next].ch[0]=0;//清除掉节点 } int K_th(int x)//查找排名为x的值 { int u=root; if(t[u].son<x)//不存在这么多个数 return false; while(2333) { int y=t[u].ch[0]; if(x>t[y].son+t[u].cnt)//在排名在u的后面 { x-=t[y].son+t[u].cnt;//直接减掉这么多 u=t[u].ch[1];//在右子树中继续找 } else if(t[y].son>=x)//如果y的节点数多于x u=y; //在左子树中继续查找 else return t[u].val;//否则找到了结果,直接返回 } } int main() { insert(-2147483647); insert(+2147483647); N=read(); while(N--) { int opt=read(); if(opt==1) insert(read()); else if(opt==2) Delete(read()); else if(opt==3) { Find(read()); printf("%d\n",t[t[root].ch[0]].son); } else if(opt==4) printf("%d\n",K_th(read()+1)); else if(opt==5) printf("%d\n",t[Next(read(),0)].val); else if(opt==6) printf("%d\n",t[Next(read(),1)].val); } return 0; }