Aqours 树 —— wblt 的替代品
前言
原文
膜拜神 @DaydreamWarrior
概述
Aqours 树是一种 2-3 leafy 树,具体而言,只有叶子节点维护了元素,其他的节点都只用来检索,其他的节点均只有
那么平衡树的基本操作如第
合并
这里指的是值域不交的合并。
假设我们合并两棵 Aqours 树
假设要把树
假若
否则,
注意到
如果递归到了根,那么再次新建一个节点
令人惊讶的是,这个过程并非简单的
并且得到的新树树高
分裂
假若要分裂成
首先在 Aqours 树上检索
我们将这条链上所有点拆开,也就是将这些点与其儿子的边全部断开。
那么剩下这条链上的一些点和这些点的儿子的子树,对于链上的拆分后孤立的非叶子节点,由于其已经没有了检索价值,直接丢掉,然后对于剩下的子树,一定是若干棵 Aqours 树(我们认为链上的叶子节点拆分完后变为一个单独的代表信息的叶子节点也算一棵 Aqours 树),由于你是从上往下拆,所以拆出来的 Aqours 树高度递减,将这些树按照全树小于等于
分析下复杂度,假若对于一个类别内子树
性质
所有叶子等深度(树高较小)。重量平衡,即父亲的子树大小至少是儿子的
相比于 wblt
貌似可以胜任同样的工作。
听发明者说他实现的版本比 wblt 更快。
实现
我实现的比较劣,常数较大。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+1e5+114;
struct Aqours_Tree{
int s[3];
int r;
int sz,height;
Aqours_Tree(){
sz=s[0]=s[1]=s[2]=0;
r=INT_MAX;
height=1;
}
}tr[maxn<<1];
int tot;
int trash[maxn<<1];
int st;
inline int clone(){
if(st>0){
int New=trash[st];
st--;
tr[New]=Aqours_Tree();
return New;
}
else return ++tot;
}
inline void pushup(int u){
if(tr[u].s[0]==0) return ;
tr[u].sz=tr[tr[u].s[0]].sz+tr[tr[u].s[2]].sz+tr[tr[u].s[1]].sz;
tr[u].r=tr[tr[u].s[1]].r;
tr[u].height=tr[tr[u].s[0]].height+1;
}
int father[60],cntf;
int Tmerge(int x,int u,int T){
while(1){
if(tr[u].s[2]==0){
tr[u].s[2]=tr[u].s[T];
tr[u].s[T]=x;
while(cntf>0) pushup(father[cntf]),cntf--;
return father[1];
}
else{
int g=clone();
tr[g].s[T]=x,tr[g].s[T^1]=tr[u].s[T];
pushup(g);
tr[u].s[T]=tr[u].s[2];
tr[u].s[2]=0;
pushup(u);
if(cntf==1){
int f=clone();
tr[f].s[T]=g,tr[f].s[T^1]=u;
tr[f].s[2]=0;
pushup(f);
return f;
}else{
x=g;
u=father[--cntf];
}
}
}
}
int merge(int u,int v){
if(u==0||v==0) return u+v;
if(tr[u].height==tr[v].height){
int g=clone();
tr[g].s[0]=u,tr[g].s[1]=v;
pushup(g);
return g;
}else if(tr[u].height>tr[v].height){
cntf=0;
while(tr[u].height>tr[v].height+1){
father[++cntf]=u;
u=tr[u].s[1];
}
father[++cntf]=u;
int res=Tmerge(v,u,1);
return res;
}else{
cntf=0;
while(tr[v].height>tr[u].height+1){
father[++cntf]=v;
v=tr[v].s[0];
}
father[++cntf]=v;
int res=Tmerge(u,v,0);
return res;
}
}
int X[60],Y[60],totX,totY;
void split(int u,int &x,int &y,int v){
if(u==0){
x=y=0;
return ;
}
x=0,y=0;
totX=totY=0;
while(tr[u].s[0]!=0){
int x=tr[u].s[0],y=tr[u].s[2],z=tr[u].s[1];
trash[++st]=u;
if(v<tr[tr[u].s[0]].r){
Y[++totY]=tr[u].s[1];
Y[++totY]=tr[u].s[2];
u=tr[u].s[0];
}else if(tr[u].s[2]!=0&&v<tr[tr[u].s[2]].r){
X[++totX]=tr[u].s[0];
Y[++totY]=tr[u].s[1];
u=tr[u].s[2];
}else{
X[++totX]=tr[u].s[0];
X[++totX]=tr[u].s[2];
u=tr[u].s[1];
}
}
if(tr[u].r<=v) X[++totX]=u;
else Y[++totY]=u;
for(int i=totX;i>=1;i--) x=merge(X[i],x);
for(int i=totY;i>=1;i--) y=merge(y,Y[i]);
}
int kth(int u,int k){
while(tr[u].s[0]!=0){
if(k<=tr[tr[u].s[0]].sz) u=tr[u].s[0];
else{
k-=tr[tr[u].s[0]].sz;
if(k<=tr[tr[u].s[2]].sz) u=tr[u].s[2];
else k-=tr[tr[u].s[2]].sz,u=tr[u].s[1];
}
}
return tr[u].r;
}
int rk(int &u,int k){
int x=0,y=0;
split(u,x,y,k-1);
int res=tr[x].sz+1;
u=merge(x,y);
return res;
}
void ins(int &u,int v){
int x=0,y=0,z=0;
split(u,y,z,v);
split(y,x,y,v-1);
if(y==0){
y=clone();
tr[y].sz=1;
tr[y].r=v;
}else{
tr[y].sz++;
}
u=merge(x,merge(y,z));
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,m,lst=0,rt=0;
int ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
int v;
cin>>v;
ins(rt,v);
}
while(m--){
int opt,v;
cin>>opt>>v;
v^=lst;
if(opt==1){
ins(rt,v);
}else if(opt==2){
int x=0,y=0,z=0;
split(rt,y,z,v);
split(y,x,y,v-1);
tr[y].sz--;
if(tr[y].sz==0) y=0;
rt=merge(x,merge(y,z));
}else if(opt==3){
(lst=rk(rt,v)),ans^=lst;
}else if(opt==4){
(lst=kth(rt,v)),ans^=lst;
}else if(opt==5){
(lst=kth(rt,rk(rt,v)-1)),ans^=lst;
}else (lst=kth(rt,rk(rt,v+1))),ans^=lst;
}
cout<<ans<<'\n';
return 0;
}