1. 程式人生 > >【模板】普通平衡樹

【模板】普通平衡樹

考題 fine col log fff 增加 ++ style ==

題目描述

您需要寫一種數據結構(可參考題目標題),來維護一些數,其中需要提供以下操作:

  1. 插入x數

  2. 刪除x數(若有多個相同的數,因只刪除一個)

  3. 查詢x數的排名(若有多個相同的數,因輸出最小的排名)

  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.每個數的數據範圍:[-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; }

【模板】普通平衡樹