模板普通平衡树
Posted Nico&11101001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板普通平衡树相关的知识,希望对你有一定的参考价值。
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
-
插入x数
-
删除x数(若有多个相同的数,因只删除一个)
-
查询x数的排名(若有多个相同的数,因输出最小的排名)
-
查询排名为x的数
-
求x的前驱(前驱定义为小于x,且最大的数)
- 求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.每个数的数据范围:[-1e7,1e7]
来源:Tyvj1728 原名:普通平衡树
用splay写的。。。。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 100004; const int INF = 0x7fffffff; struct Splay { #define root e[0].ch[1] struct node { int v,father; int ch[2]; int sum; int recy; } e[maxn]; int n,points;//使用存储数,元素数 Splay() { n=0; points=0; } void update(int x) { e[x].sum=e[e[x].ch[0]].sum+e[e[x].ch[1]].sum+e[x].recy; } int indentify(int x) { return e[e[x].father].ch[0]==x?0:1; } void connect(int x,int f,int son) { e[x].father=f; e[f].ch[son]=x; } void destroy(int x) { e[x].v=e[x].ch[0]=e[x].ch[1]=e[x].sum=e[x].recy=e[x].father=0; if(x==n)n--; return ; } int cerpoint(int v,int father) { e[++n].father=father; e[n].v=v; e[n].recy=e[n].sum=1; return n; } void rotate(int x) { int y=e[x].father; int mroot=e[y].father; int mrootson=indentify(y); int yson=indentify(x); int B=e[x].ch[yson^1]; connect(B,y,yson); connect(y,x,(yson^1)); connect(x,mroot,mrootson); update(y); update(x); } void splay(int at,int v) { v=e[v].father; while(e[at].father!=v) { int up=e[at].father; if(e[up].father==v)rotate(at); else if(indentify(up)==indentify(at)) { rotate(up); rotate(at); } else { rotate(at); rotate(at); } } } int find(int v) { int now=root; while(11101001) { if(e[now].v==v) { splay(now,root); return now; } int next=v<e[now].v?0:1; now=e[now].ch[next]; if(!now)return 0; } } int build(int v) { points++; if(n==0) { root=1; cerpoint(v,0); return 0; } int now=root; while(11101001) { //向下找到一个空节点 e[now].sum++;//自己的下级肯定增加了一个节点 if(v==e[now].v) { e[now].recy++; return now; } int next = v<e[now].v?0:1; if(!e[now].ch[next]) { cerpoint(v,now); e[now].ch[next]=n; return n; } now=e[now].ch[next]; } return 0; } void insert(int x) { //插入元素时,先添加节点,再进行伸展 int cc=build(x); splay(cc,root); } void pop(int v) { int dd=find(v); if(!dd)return ; points--; if(e[dd].recy>1) { e[dd].recy--; e[dd].sum--; return; } if(!e[dd].ch[0]) { root=e[dd].ch[1]; e[root].father=0; } else { int l=e[dd].ch[0]; while(e[l].ch[1])l=e[l].ch[1]; splay(l,e[dd].ch[0]); int r=e[dd].ch[1]; connect(r,l,1); connect(l,0,1); update(l); } destroy(dd); } int rank(int v) { //获取值为v的元素在这棵树里是第几小 int ans=0,now=root; while(11101001) { if(e[now].v==v)return ans+e[e[now].ch[0]].sum+1; if(now==0)return 0; if(v<e[now].v)now=e[now].ch[0]; else { ans+=e[e[now].ch[0]].sum+e[now].recy, now=e[now].ch[1]; } } } int atrank(int x) { if(x>points)return -INF; int now=root; while(11101001) { int min_used=e[now].sum-e[e[now].ch[1]].sum; if(x>e[e[now].ch[0]].sum&&x<=min_used)break; if(x<min_used)now=e[now].ch[0]; else { x=x-min_used; now=e[now].ch[1]; } } splay(now,root); return e[now].v; } int upper(int v) { int now=root; int ans=INF; while(now) { if(e[now].v>v&&e[now].v<ans)ans=e[now].v; if(v<e[now].v)now=e[now].ch[0]; else now=e[now].ch[1]; } return ans; } int lower(int v) { int now=root; int ans=-INF; while(now) { if(e[now].v<v&&e[now].v>ans)ans=e[now].v; if(v>e[now].v)now=e[now].ch[1]; else now=e[now].ch[0]; } return ans; } } splay; int main() { int n; scanf("%d",&n); int a,b; for(int i=1; i<=n; i++) { scanf("%d%d",&a,&b); if(a==1) { splay.insert(b); } if(a==2) { splay.pop(b); } if(a==3) { printf("%d\n",splay.rank(b)); } if(a==4) { printf("%d\n",splay.atrank(b)); } if(a==5) { printf("%d\n",splay.lower(b)); } if(a==6) { printf("%d\n",splay.upper(b)); } } return 0; }
以上是关于模板普通平衡树的主要内容,如果未能解决你的问题,请参考以下文章