变量/函数の定义
变量/函数名 |
定义/作用 |
tax[] |
将树拍扁时用的临时数组 |
tail |
与 tax[] 配套使用,类似于栈顶指针 |
son[x][] |
点 \(x\) 在树上的左/右儿子 |
exist[x] |
点 \(x\) 存在与否,\(1\) 为存在 |
val[x] |
点 \(x\) 的值 |
siz[x] |
点 \(x\) 的子树一共有多少节点 |
fact[x] |
点 \(x\) 的子树实际还存在多少节点 |
rt |
树根 |
memory_pool[] |
内存池 |
origami |
记录内存池的元素个数,也用作栈顶指针真不是折纸大师 |
void buildPool() |
建立内存池 |
int Newnode() |
获取一个新节点编号 |
void Release(x) |
释放节点 \(x\),即重新放回内存池 |
void Clear(x) |
将点 \(x\) 清空 |
void Leaf(x) |
建立点 \(x\) 为叶子的信息,双儿子为 \(0\) 且子树大小为 \(1\) |
void Pushup(x) |
顾名思义,上传操作 |
bool Balance(x) |
返回树 \(x\) 平衡与否,\(1\) 为平衡 |
void Insert(x,v) |
在点 \(x\) 的子树里面插入值 \(v\) |
void Delete(x,rnk) |
在点 \(x\) 的子树里面删除排名为 \(rnk\) 的值 |
int Getrnk(v) |
获得值 \(v\) 在整棵树里的排名 |
int Getval(rnk) |
获得树里排名为 \(rnk\) 的值 |
void Recycle(x) |
回收/拍扁以 \(x\) 为根的树 |
void Setup(x,l,r) |
以 \(x\) 为树根,在 tax[] 的 \(l\) 到 \(r\) 区间中重新建树 |
void Rebuild(x) |
重建子树 \(x\) |
void Check(v) |
在树插入/删除 \(v\) 之后检查树的平衡性 |
代码
/*
* @Author: Arextre
* @Date: 2020-03-13 10:42:22
* @Last Modified by: Arextre
* @Last Modified time: 2020-03-14 10:35:15
*/
#include<cstdio>
#include<vector>
using namespace std;
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
// #define FILEOI
// #define int long long
// #define int unsigned
// #define int unsigned long long
#ifdef FILEOI
# define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
# undef MAXBUFFERSIZE
# define cg (c=fgetc())
#else
# define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
// template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const double ALPHA=0.7;
const int INF=0x3f3f3f3f;
const int MAXN=100000;
int tax[MAXN+5],tail;
int son[MAXN+5][2],exist[MAXN+5],val[MAXN+5],siz[MAXN+5],fact[MAXN+5],rt;
int memory_pool[MAXN+5],origami;//内存池
inline void buildPool(){
origami=0;
fep(i,MAXN,1)memory_pool[++origami]=i;
}
inline int Newnode(){
return memory_pool[origami--];
}
inline void Release(const int x){memory_pool[++origami]=x;}
inline void Clear(const int x){
son[x][0]=son[x][1]=exist[x]=val[x]=siz[x]=fact[x]=0;
}
inline void Leaf(const int x){
son[x][0]=son[x][1]=0,siz[x]=fact[x]=1;
}
inline void Pushup(const int x){
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
fact[x]=fact[son[x][0]]+fact[son[x][1]]+1;
}
inline bool Balance(const int x){
return (double)fact[x]*ALPHA>(double)Max(fact[son[x][0]],fact[son[x][1]]);
}
void Insert(int& x,const int v){
if(!x){
Clear(x=Newnode());
val[x]=v,exist[x]=1;
Leaf(x);
return;
}
++siz[x],++fact[x];
if(v<=val[x])Insert(son[x][0],v);
else Insert(son[x][1],v);
}
void Delete(const int x,const int rnk){
--fact[x];
if(exist[x] && fact[son[x][0]]+1==rnk){
exist[x]=0;
return;
}
if(rnk<=fact[son[x][0]]+exist[x])Delete(son[x][0],rnk);
else Delete(son[x][1],rnk-fact[son[x][0]]-exist[x]);
}
inline int Getrnk(const int v){
int x=rt,rnk=1;
while(x){
if(v<=val[x])x=son[x][0];
else rnk+=fact[son[x][0]]+exist[x],x=son[x][1];
}
return rnk;
}
inline int Getval(int rnk){
if(rnk<1 || fact[rt]<rnk)return -INF;
int x=rt;
while(x){
if(exist[x] && fact[son[x][0]]+1==rnk)return val[x];
else if(rnk<=fact[son[x][0]]+exist[x])x=son[x][0];
else rnk-=(fact[son[x][0]]+exist[x]),x=son[x][1];
}
}
void Recycle(const int x){
if(!x)return;
Recycle(son[x][0]);
if(exist[x])tax[++tail]=x;
else Release(x);
Recycle(son[x][1]);
}
void Setup(int& x,const int l,const int r){
int mid=(l+r)>>1;x=tax[mid];
if(l==r)return Leaf(x);
if(l<mid)Setup(son[x][0],l,mid-1);
else son[x][0]=0;//此句十分关键
Setup(son[x][1],mid+1,r);
Pushup(x);
}
inline void Rebuild(int& x){
tail=0;Recycle(x);
if(tail>0)Setup(x,1,tail);
else x=0;
}
inline void Check(const int v){
if(!Balance(rt))return Rebuild(rt);
int x=rt,d=(v>val[rt]);
while(son[x][d]){
if(!Balance(son[x][d]))return Rebuild(son[x][d]);
x=son[x][d];
d=(v>val[x]);
}
}
int n,opt,x;
signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
scanf("%d",&n);
buildPool();
while(n--){
scanf("%d %d",&opt,&x);
if(opt==1)Insert(rt,x),Check(x);
else if(opt==2)Delete(rt,Getrnk(x)),Check(x);
else if(opt==3)printf("%d\n",Getrnk(x));
else if(opt==4)printf("%d\n",Getval(x));
else if(opt==5)printf("%d\n",Getval(Getrnk(x)-1));
else if(opt==6)printf("%d\n",Getval(Getrnk(x+1)));//注意+1细节
}
return 0;
}