splay完整模板:

#include<iostream>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
const int M=1e5+10;
int son[M][2],siz[M],cnt[M],fa[M],key[M],root;
bool getf(int x){//查询当前节点是父亲节点的左儿子还是右儿子
    return son[fa[x]][1]==x;
}
void update(int x){//更新节点的siz值(即子树大小)
    siz[x]=cnt[x];
    if(son[x][0])siz[x]+=siz[son[x][0]];
    if(son[x][1])siz[x]+=siz[son[x][1]];
}
void rotate(int x){//旋转
    int f=fa[x],ff=fa[f];
    bool d=getf(x),dd=getf(f);
    son[f][d]=son[x][!d];fa[son[f][d]]=f;
    son[x][!d]=f;fa[f]=x;
    fa[x]=ff;son[ff][dd]=x;
    update(x);
    update(f);
}
void splay(int x,int goal){//将某个节点旋转到目标节点的儿子处
    while(fa[x]!=goal){
        int f=fa[x],ff=fa[f];
        if(ff!=goal)rotate(getf(f)==getf(x)?f:x);
        rotate(x);
    }
    if(goal==0)root=x;
}
int tot=0;
void insert(int x){//插入一个数
    if(root==0){
        int t=++tot;
        fa[t]=0;cnt[t]=siz[t]=1;son[t][0]=son[t][1]=0;
        key[t]=x;
        root=t;
        return;
    }
    int u=root;
    while(1){
        if(key[u]==x){
            cnt[u]++;siz[u]++;
            return;
        }
        if(x<key[u]){
            if(son[u][0])siz[u]++,u=son[u][0];
            else{
                int t=++tot;
                son[u][0]=t;
                key[t]=x;cnt[t]=siz[t]=1;siz[u]++;
                son[t][0]=son[t][1]=0;
                fa[t]=u;
                splay(t,0);
                return;
            }
        }
        else{
            if(son[u][1])siz[u]++,u=son[u][1];
            else{
                int t=++tot;
                son[u][1]=t;
                key[t]=x;cnt[t]=siz[t]=1;siz[u]++;
                son[t][0]=son[t][1]=0;
                fa[t]=u;
                splay(t,0);
                return;
            }
        }
    }
}
int query_rank(int x){//查询x的排名
    int u=root,ans=0;
    while(1){
        if(key[u]==x){
            if(son[u][0])ans+=siz[son[u][0]];
            return ans+1;
        }
        if(x<key[u])u=son[u][0];
        else{
            if(son[u][0])ans+=siz[son[u][0]];
            ans+=cnt[u];u=son[u][1];
        }
    }
}
int find_rank(int x){//查询排名为x的数
    int u=root;
    while(1){
        int y=son[u][0]?siz[son[u][0]]:0;
        if(x<=y)u=son[u][0];
        else if(x>y+cnt[u])x-=siz[son[u][0]]+cnt[u],u=son[u][1];
        else return key[u];
    }
}
int Find(int x){//查找数x的位置
    int u=root;
    while(1){
        if(key[u]==x)return u;
        if(x<key[u])u=son[u][0];
        else u=son[u][1];
    }
}
int pre(int x){//返回中序遍历中某个节点的前驱节点(先splay到根)
    splay(Find(x),0);
    int u=son[root][0];
    while(son[u][1])u=son[u][1];
    return u;
}
int query_pre(int x){//查询x的前驱(小于x的最大值)
    int u=root,MAX;
    while(1){
        if(key[u]>=x){
            if(son[u][0])u=son[u][0];
            else return MAX;
        }
        else{
            MAX=key[u];
            if(son[u][1])u=son[u][1];else return MAX;
        }
    }
}
int query_next(int x){//查询x的后继(大于x的最小值)
    int u=root,MIN;
    while(1){
        if(key[u]<=x){
            if(son[u][1])u=son[u][1];
            else return MIN;
        }
        else{
            MIN=key[u];
            if(son[u][0])u=son[u][0];else return MIN;
        }
    }
}
void del(int x){//删除数x(有多个只删除其中一个)
    int u=Find(x);
    splay(u,0);
    if(cnt[u]>1){
        cnt[u]--;siz[u]--;
        return;
    }
    if(!son[root][0]&&!son[root][1])root=0;
    else if(!son[root][0])root=son[root][1],fa[root]=0;
    else if(!son[root][1])root=son[root][0],fa[root]=0;
    else{
        int newroot=pre(x),oldroot=root;
        splay(newroot,0);
        son[root][1]=son[oldroot][1];
        fa[son[root][1]]=root;
        update(root);
    }
}
int main(){
    int n;scanf("%d",&n);
    while(n--){
        int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1)insert(x);
        else if(opt==2)del(x);
        else if(opt==3)printf("%d\n",query_rank(x));
        else if(opt==4)printf("%d\n",find_rank(x));
        else if(opt==5)printf("%d\n",query_pre(x));
        else printf("%d\n",query_next(x));
    }
    return 0;
}

平衡树的应用——区间翻转:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<algorithm>
#include<cmath>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
const int M=1e5+10;
int son[M][2]={0},fa[M],siz[M],cnt[M],key[M];
int n,m,root;
bool tag[M]={0};
void clear(int x){
    son[x][0]=son[x][1]=fa[x]=siz[x]=cnt[x]=0;
}
bool getf(int x){
    return son[fa[x]][1]==x;
}
void update(int x){
    siz[x]=cnt[x];
    if(son[x][0])siz[x]+=siz[son[x][0]];
    if(son[x][1])siz[x]+=siz[son[x][1]];
}
void rotate(int x){
    int f=fa[x],ff=fa[f];bool d=getf(x);
    son[f][d]=son[x][!d];fa[son[x][!d]]=f;
    son[x][!d]=f;fa[f]=x;
    son[ff][son[ff][1]==f]=x;fa[x]=ff;
    update(f);update(x);
}
void splay(int x,int goal){//将x旋转到目标位置
    while(fa[x]!=goal){
        int f=fa[x],ff=fa[f];
        if(ff!=goal)rotate(getf(x)==getf(f)?f:x);
        rotate(x);
    }
    if(goal==0)root=x;
}
int tot=0;
void build(int l,int r,int f,int g){//构造完美平衡树
    int t=++tot;
    son[f][g]=t;fa[t]=f;cnt[t]=1;
    int mid=(l+r)>>1;key[t]=mid;
    if(l==r){
        siz[t]=1;
        return;
    }
    if(l<mid)build(l,mid-1,t,0);
    if(mid<r)build(mid+1,r,t,1);
    update(t);
}
void pushdown(int u){
    if(son[u][0])tag[son[u][0]]^=1;
    if(son[u][1])tag[son[u][1]]^=1;
    tag[u]=0;swap(son[u][0],son[u][1]);
}
int Find(int x){
    int u=root;
    while(1){
        if(tag[u])pushdown(u);
        if(siz[son[u][0]]==x-1){
            //cout<<key[u];
            return u;
        }
        if(siz[son[u][0]]<x-1)x-=siz[son[u][0]]+1,u=son[u][1];
        else u=son[u][0];
    }
}
void print(int x){//按中序遍历打印平衡树
    if(tag[x])pushdown(x);
    if(son[x][0])print(son[x][0]);
    if(key[x]&&key[x]<=n)printf("%d ",key[x]);
    if(son[x][1])print(son[x][1]);
}
int main(){
    scanf("%d%d",&n,&m);
    build(0,n+1,0,0);root=1;
    while(m--){
        int l,r;scanf("%d%d",&l,&r);
        l=Find(l);r=Find(r+2);
        splay(l,0);splay(r,l);
        tag[son[son[root][1]][0]]^=1;//翻转区间时在子树的根上打标记
        //print(root);
    }
    print(root);
}