【模板】普通平衡樹
題目描述
您需要動態地維護一個可重集合 \(M\),並且提供以下操作:
- 向 \(M\) 中插入一個數 \(x\)。
- 從 \(M\) 中刪除一個數 \(x\)(若有多個相同的數,應只刪除一個)。
- 查詢 \(M\) 中有多少個數比 \(x\) 小,並且將得到的答案加一。
- 查詢如果將 \(M\) 從小到大排列後,排名位於第 \(x\) 位的數。
- 查詢 \(M\) 中 \(x\) 的前驅(前驅定義為小於 \(x\),且最大的數)。
- 查詢 \(M\) 中 \(x\) 的後繼(後繼定義為大於 \(x\),且最小的數)。
對於操作 3,5,6,不保證當前可重集中存在數 \(x\)。
輸入格式
第一行為 \(n\),表示操作的個數,下面 \(n\) 行每行有兩個數 \(\text{opt}\) 和 \(x\),\(\text{opt}\) 表示操作的序號($ 1 \leq \text{opt} \leq 6 $)
輸出格式
對於操作 \(3,4,5,6\) 每行輸出一個數,表示對應答案。
樣例 #1
樣例輸入 #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
提示
【資料範圍】
對於 \(100\%\) 的資料,\(1\le n \le 10^5\),\(|x| \le 10^7\)
來源:Tyvj1728 原名:普通平衡樹
在此鳴謝
分析
模板
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100,M=1e6+100;
struct node
{
int lc,rc,pre,val,siz;
}t[N];
int tot,root,n;
void create(int x)
{
++tot;
t[tot].lc=t[tot].rc=0;
t[tot].val=x;
t[tot].siz=1;
t[tot].pre=rand();
}
void upd(int x)
{
t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+1;
}
void split(int u,int x,int &L,int &R)
{
if(u==0){L=R=0;return ;}
if(t[u].val<=x)
{
L=u;
split(t[u].rc,x,t[u].rc,R);
}
else
{
R=u;
split(t[u].lc,x,L,t[u].lc);
}
upd(u);
}
int merg(int L,int R)
{
if(L==0 || R==0)return L+R;
if(t[L].pre>t[R].pre)
{
t[L].rc=merg(t[L].rc,R);
upd(L);
return L;
}
else
{
t[R].lc=merg(L,t[R].lc);
upd(R);
return R;
}
}
void inser(int x)
{
int L=0,R=0;
create(x);
split(root,x,L,R);
L=merg(L,tot);
root=merg(L,R);
}
void del(int x)
{
int L=0,R=0,nw=0;
split(root,x,L,R);
split(L,x-1,L,nw);
nw=merg(t[nw].lc,t[nw].rc);
L=merg(L,nw);
root=merg(L,R);
}
int finx(int x)
{
int L=0,R=0,nw=0;
split(root,x-1,L,R);
nw=t[L].siz+1;
root=merg(L,R);
return nw;
}
int rk(int u,int k)
{
if(t[t[u].lc].siz+1==k)return u;
if(t[t[u].lc].siz>=k)return rk(t[u].lc,k);
else return rk(t[u].rc,k-t[t[u].lc].siz-1);
}
int pre_x(int x)
{
int L=0,R=0,nw=0;
split(root,x-1,L,R);///L==0 -->RE
nw=t[ rk(L,t[L].siz) ] .val;
root=merg(L,R);
return nw;
}
int suf_x(int x)
{
int L=0,R=0,nw=0;
split(root,x,L,R);
nw=t[ rk(R,1) ] .val;
root=merg(L,R);
return nw;
}
void work()
{
cin>>n;
int opt,x;
while(n--)
{
scanf("%d%d",&opt,&x);
if(opt==1)inser(x);
else if(opt==2)del(x);
else
{
int ans=0;
if(opt==3)ans=finx(x);
else if(opt==4)ans=t[rk(root,x)].val;
else if(opt==5)ans=pre_x(x);
else ans=suf_x(x);
printf("%d\n",ans);
}
}
}
int main()
{
work();
return 0;
}