「模板」替罪羊树

变量/函数の定义

变量/函数名 定义/作用
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;
}
posted @ 2020-03-14 10:56  Arextre  阅读(128)  评论(0编辑  收藏  举报