平衡树 区间树 学习

前记

把之前学的平衡树都写一下,最近更新:Splay

Treap

本人的Treap丢了,放之前学习的Treap看看

#include<bits/stdc++.h>
using namespace std;
struct Treap{
    static const int MAXN=400000+10;
    static const int INF=2000000000;
    struct Node{
        int val;
        int pri;
        int cnt;
        int r,l;
        int size;
    }tree[MAXN];
    int root;
    int top;
    Treap(){
        root=0;
        top=0;
    }
    void update(int node){                  //  更新 node 的 size 值,相当于 Segment Tree 的 pushup 
        tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size+tree[node].cnt;
    }
    
    void zig(int& node)                     //  左旋,可以看到会修改 node 的值,因此传入了一个引用 
    {
        int root=tree[node].r;
        tree[node].r=tree[root].l;
        tree[root].l=node;
        update(node);
        update(root);
        node=root;
    }
    
    void zag(int& node)                     //  右旋 
    {
        int root=tree[node].l;
        tree[node].l=tree[root].r;
        tree[root].r=node;
        update(node);
        update(root);
        node=root;
    }
    
    void insert(int& node,int x)            //  在 node 中插入 x 
    {
        if(!node){                          //新建结点 
            node=++top;                     //深度++,结点编号 
            tree[node].pri=rand();          //随机优先值 
            tree[node].val=x;               //节点值 
            tree[node].size=0;              //子数大小 
            tree[node].cnt=0;               //计相同数的个数 
            tree[node].l=tree[node].r=0;    //初始化左、右子数大小 
        }
        tree[node].size++;
        if(tree[node].val==x){              //发现相同结点 
            tree[node].cnt++;               //相同结点数++           
        }
        else 
        if(tree[node].val>x)                //往左子树走 
        {
            insert(tree[node].l,x);
            if(tree[node].pri>tree[tree[node].l].pri)   //按优先级旋转treap 
                zag(node);//右旋 
        }
        else                                //往右子树走 
        {
            insert(tree[node].r,x);
            if(tree[node].pri>tree[tree[node].r].pri)   //按优先级旋转treap 
                zig(node);//左旋 
        }
        //update(node);                     //更新 
    }
    
    bool erase(int& node,int x)             //删除 x 
    {
        if(!node)//空就返回 
            return false;
        if(tree[node].val==x)               //删除 
        {
            tree[node].size--;
            if(tree[node].cnt>1){
                tree[node].cnt--;
            }
            else 
            if(tree[node].l==0||tree[node].r==0){//更新结点 
                node=tree[node].l+tree[node].r;
            }
            else 
            if(tree[tree[node].l].pri<tree[tree[node].r].pri)
            {//按优先级旋转treap 
                zag(node);
                erase(node,x);              //更新旋转后结点 
            }
            else
            {
                zig(node);
                erase(node,x);              //更新旋转后结点
            }
            return true;
        }
        else                                //往下找结点 
        {
            bool flag;
            if(tree[node].val>x){
                flag=erase(tree[node].l,x);
            }
            else{
                flag=erase(tree[node].r,x);
            }
            if(flag)
            tree[node].size--; 
            return flag; 
        }
    }

    int rank(int node,int x)                //查询排名为xx的数,  有多少个数比x小,记得加1 
    {
        if(tree[node].val==x){              //找到返回左子树大小 ,左子数的所以结点必定小于根和右子树结点(BST性质 
            return tree[tree[node].l].size;
        }
        else if(tree[node].val<x){          //递归右子树找点,更新排名 
            return tree[tree[node].l].size+rank(tree[node].r,x)+tree[node].cnt;
        }
        else{
            return rank(tree[node].l,x);    //递归左子树找点,更新排名 
        }
    }
    
    int k_th(int node,int k)                //  第 k 小数 
    {
        if(k<=tree[tree[node].l].size)
            return k_th(tree[node].l,k);
        k-=tree[tree[node].l].size+tree[node].cnt;
        if(k<=0)
            return tree[node].val;
        else
            return k_th(tree[node].r,k);
    }
    
    int pre(int x)                          //  前驱,即最接近 x 但又比它小的数 
    {
        int max1=-INF,node=root;
        while(node)
        {
            if(tree[node].val<x){           // 如果该结点值小于x,更新最大值,往右继续找(往大的找  
                max1=max(max1,tree[node].val);
                node=tree[node].r;
            }
            else                            // 否则往左找(往小的找 
                node=tree[node].l;
        }
        return max1;
    }

    int suf(int x)                          //  后继,代码很接近前驱 
    {
        int min1=INF,node=root;
        while(node){
            if(tree[node].val>x){           // 如果该结点值大于x,更新最小值,往左继续找(往小的找  
                min1=min(min1,tree[node].val);
                node=tree[node].l;
            }
            else
                node=tree[node].r;          // 否则往右找(往大的找 
        }
        return min1;
    }
    //  遍历整棵树,输出
    //  输出格式为 “节点值(x节点个数)” 
    void print(int node,int level){
        if(!node)  return;
        print(tree[node].l,level+1);
        cout<<tree[node].val<<" (x"<<tree[node].cnt<<"), ";
        print(tree[node].r,level+1);
        cout<<endl; 
    }
}T;
int main(){
    srand(time(0));
    //  命令的含义应该能看懂吧
    //  命令必须合法,没加不合法鲁棒
    //  不合法命令可能会出现 Runtime Error 或者魔改 Treap 
    //  命令的格式是:“命令 值” 
    //cout<<"Commands list: del / ins / pre / suf / rnk / kth (Maybe error)"<<endl;
    int G;
    ios::sync_with_stdio(0);
    cin>>G;
    while(G--)
    {
        //cout<<"Print: ";
        //T.print(T.root,1);            遍历整棵树,输出
        string m;
        int x;
        cin>>m>>x;
        if(m=="del"||m=="2")
            T.erase(T.root,x);
        else 
        if(m=="ins"||m=="1")
            T.insert(T.root,x);
        else 
        if(m=="pre"||m=="5")
            cout<<T.pre(x)<<endl;
        else 
        if(m=="suf"||m=="6")
            cout<<T.suf(x)<<endl;
        else 
        if(m=="rnk"||m=="3")
            cout<<T.rank(T.root,x)+1<<endl;
        else 
        if(m=="kth"||m=="4")
            cout<<T.k_th(T.root,x)<<endl;
    }
    return 0;
}

FHQ-Treap

//FHQtreap
#include<bits/stdc++.h>
#define maxn 1000001
using namespace std;
int n,x,y,mode,cnt,root;
struct kkk{
    int size,val,pri,l,r;
}tree[maxn];
////////////////////////////////////////////////////////////////////////////
int New(int val){
    tree[++cnt].size=1;
    tree[cnt].val=val;
    tree[cnt].pri=rand();
    tree[cnt].l=tree[cnt].r=0;
    return cnt;
}
void update(int node){
    tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size+1;
}
void spilt(int node,int &x,int &y,int val){
    if(node==0){
        x=y=0;return;
    }
    if(tree[node].val<=val){
        x=node;spilt(tree[node].r,tree[x].r,y,val);
    }else{
        y=node;spilt(tree[node].l,x,tree[y].l,val);
    }
    update(node);
}
int merge(int x,int y){
    if(!x||!y)return x+y;
    if(tree[x].pri<tree[y].pri){
        tree[x].r=merge(tree[x].r,y);
        update(x);
        return x;
    }else{
        tree[y].l=merge(x,tree[y].l);
        update(y);
        return y;
    }
}
void find(int node,int val){
    while(tree[tree[node].l].size+1!=val){
        if(tree[tree[node].l].size>=val)
            node=tree[node].l;
        else
            val-=tree[tree[node].l].size+1,node=tree[node].r;
    }
    printf("%d\n",tree[node].val);
}
////////////////////////////////////////////////////////////////////////////
void insert(int val){
    int x=0,y=0,z=0;
    z=New(val);
    spilt(root,x,y,val);
    x=merge(x,z);
    root=merge(x,y);
}
void del(int val){
    int x=0,y=0,z=0;
    spilt(root,x,y,val);
    spilt(x,x,z,val-1);
    z=merge(tree[z].l,tree[z].r);
    x=merge(x,z);
    root=merge(x,y);
}
void rank(int val){
    int x=0,y=0;
    spilt(root,x,y,val-1);
    printf("%d\n",tree[x].size+1);
    root=merge(x,y);
}
void pre(int val){
    int x=0,y=0;
    spilt(root,x,y,val-1);
    find(x,tree[x].size);
    root=merge(x,y);
}
void suf(int val){
    int x=0,y=0;
    spilt(root,x,y,val);
    find(y,1);
    root=merge(x,y);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&mode,&x);
        if(mode==1)insert(x);
        if(mode==2)del(x);
        if(mode==3)rank(x);
        if(mode==4)find(root,x);
        if(mode==5)pre(x);
        if(mode==6)suf(x);
    }
}

FHQ-Treap 文艺平衡树

//FHQtreap
#include<bits/stdc++.h>
#define maxn 1000001
using namespace std;
int n,m,x,y,mode,cnt,root,tag[maxn];
struct kkk{
    int size,val,pri,l,r;
}tree[maxn];
////////////////////////////////////////////////////////////////////////////
int New(int val){
    tree[++cnt].size=1;
    tree[cnt].val=val;
    tree[cnt].pri=rand();
    tree[cnt].l=tree[cnt].r=0;
    return cnt;
}
void pushdown(int x){
    tag[x]^=1;
    swap(tree[x].l,tree[x].r);
    tag[tree[x].l]^=1;tag[tree[x].r]^=1;
}
void update(int node){
    tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size+1;
}
void spilt(int node,int &x,int &y,int val){
    if(node==0){
        x=y=0;return;
    }
    if(tag[node])pushdown(node);
    if(val>tree[tree[node].l].size){
        x=node;spilt(tree[node].r,tree[node].r,y,val-tree[tree[node].l].size-1);
    }else{
        y=node;spilt(tree[node].l,x,tree[node].l,val);
    }
    update(node);
}
int merge(int x,int y){
    if(!x||!y)return x+y;
    if(tag[x])pushdown(x);
    if(tag[y])pushdown(y);
    if(tree[x].pri<tree[y].pri){
        tree[x].r=merge(tree[x].r,y);
        update(x);
        return x;
    }else{
        tree[y].l=merge(x,tree[y].l);
        update(y);
        return y;
    }
}
////////////////////////////////////////////////////////////////////////////
void insert(int val){
    int x=0,y=0,z=0;
    z=New(val);
    spilt(root,x,y,val);
    x=merge(x,z);
    root=merge(x,y);
}
void rotate(int x,int y){
    int a,b,c,d;
    spilt(root,a,b,y+1);
    spilt(a,c,d,x);
    tag[d]^=1;
    root=merge(merge(c,d),b);
}
void print(int x){
    if(tag[x])pushdown(x);
    if(tree[x].l)print(tree[x].l);
    printf("%d ",tree[x].val);
    if(tree[x].r)print(tree[x].r);
}
int main(){
    //srand(time(0));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)insert(i);
    //print(root);cout<<endl;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        rotate(x-1,y-1);
        //cout<<endl;print(root);cout<<endl;
    }
    print(root);
}

IST 文艺平衡树

#include<bits/stdc++.h>
#define maxn 1000001            //不知道为什么我就是喜欢开怎么大,其实完全没必要 
using namespace std;
struct kkk{
    int l,r,tag,x,size;
}tree[maxn];
int t[maxn],Left[maxn],middle[maxn],Right[maxn],rub[maxn],tmp[maxn];
int n,m,x,y,tot,top,le,ri,mi,root;
inline int read(){              //快读,形成好习惯 
   int s=0,w=1;
   char ch=getchar();
   while(ch<='0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int New(){  //新建节点 
    int pos=rub[tot--];
    tree[pos].l=tree[pos].r=tree[pos].size=tree[pos].x=tree[pos].tag=0;
    return pos;
}
void pushdown(int node){    //pushdown 
    if(tree[node].tag){         //如果有标记就操作 
        tree[node].tag=0;       //原标记清0,和线段树一样 
        tree[tree[node].l].tag^=1;  //左标记取相反值,就是0变成1,1变成0 
        swap(tree[tree[node].l].l,tree[tree[node].l].r);    //交换左子树的左右孩子,因为要翻转嘛 
        tree[tree[node].r].tag^=1;  //右标记取相反值
        swap(tree[tree[node].r].l,tree[tree[node].r].r);    //交换右子树的左右孩子
    }
}
void pushup(int node){      //pushup 
    tree[node].size=tree[tree[node].l].size+tree[tree[node].r].size;
}
void spilt(int node,int begin,int end,int x,int y){         //分裂 
    if(end<x){Left[++le]=node;return;}  //如果查询区间在要修改区间左部,并入左数组 
    if(x<=begin&&end<=y){middle[++mi]=node;return;} //如果查询区间在要修改区间中,并入中数组 
    if(y<begin){Right[++ri]=node;return;}   //如果查询区间在要修改区间右部,并入右数组 
    pushdown(node);                     //pushdown更新tag标记 
    int mid=begin+tree[tree[node].l].size-1;    //注意,因为经过修改后的树不像线段树那么平衡,所以mid值有所变动 
    spilt(tree[node].l,begin,mid,x,y);      //向左子树递归分裂 
    spilt(tree[node].r,mid+1,end,x,y);      //向左子树递归分裂 
    rub[++tot]=node;                    //这里是垃圾回收 
}
void marge(){                   //合并 
    int cnt=0;  //记得数组清0,要按顺序合并哦 
    for(int i=1;i<=le;++i)t[++cnt]=Left[i]; //把左部分合并 
    for(int i=1;i<=mi;++i)t[++cnt]=middle[i];   //把中部分合并 
    for(int i=1;i<=ri;++i)t[++cnt]=Right[i];    //把右部分合并 
    while(cnt>1){   //重新建树过程 
        int mid=(cnt+1)/2;  //取mid值
        for(int i=1;i<=mid;++i){    //将线段树底部节点一一合并 
            int x=t[i*2-1],y=t[i*2];
            if(!x||!y)t[i]=x+y; //如果有一个是空,特判 
            else{
                int node=New(); //新建一个节点 
                tree[node].l=x;tree[node].r=y;  //新节点指儿子 
                pushup(node);   //pushup 
                t[i]=node;      //把新节点并入数组里 
            }
        }
        for(int i=mid+1;i<=cnt;++i)t[i]=0;//记得把剩下节点清0,原因是他们已经在上面合并过了,而且避免了奇偶的错误 
        cnt=(cnt+1)/2;  //到下一层继续建树 
    }root=t[1];         //根更新 
}
void build(int node,int l,int r){   //建树 
    if(l==r){
        tree[node].x=l; //初值是i嘛 
        tree[node].size=1;  //树大小是1 
        return; 
    }int mid=(l+r)>>1;  //和线段树一毛一样 
    tree[node].l=++top; //新建左子树的编号 
    build(top,l,mid);   //递归左子树建树 
    tree[node].r=++top; //新建右子树的编号 
    build(top,mid+1,r); //递归右子树建树 
    pushup(node);       //pushup
}
void rotate(int x,int y){       //翻转 
    le=0,ri=0,mi=0;     //记得左,中,右部分数组要清0 
    spilt(root,1,tree[root].size,x,y);  //分裂 
    for(int i=1;i<=mi;++i)tmp[i]=middle[i]; //把中部分提取出来 
    for(int i=1;i<=mi;++i){
        middle[i]=tmp[mi-i+1];          //翻过来,就是直接赋值嘛 
        tree[middle[i]].tag^=1;         //打标记 
        swap(tree[middle[i]].l,tree[middle[i]].r);  //交换左右子树 
    }marge();           //合并 
}
void print(int node){           //输出 
    pushdown(node);     //pushdown 
    if(tree[node].size==1){
        printf("%d ",tree[node].x);             //输出 
        return ;
    }print(tree[node].l);print(tree[node].r);   //递归左右子树 
}
int main(){
    n=read();m=read();root=top=1;   //记得赋初值 
    build(1,1,n);           //建树 
    for(int i=1;i<=m;++i){
        x=read();y=read();  
        rotate(x,y);        //翻转 
    }print(root);           //输出 
}

替罪羊树

思想:当平衡树不平衡时就重构

//替罪羊树 P3369 【模板】普通平衡树
#include<bits/stdc++.h>
#define maxn 1000000                //数组大小
#define alpha 0.75                  //替罪羊常数
#define L(x) tree[x].l              //左儿子
#define R(x) tree[x].r              //右儿子
#define F(x) tree[x].fa             //父亲
using namespace std;
struct Node{
    int l,r,val,fa,size,sum,cnt;
    // l 表示 左儿子 , r 表示 右儿子 ,val 表示 值 , fa 表示 父亲
    // size 表示 子树节点和 , cnt 表示 相同val的数量 , sum 表示 子树所有 cnt 的和
}tree[maxn],seq[maxn];
int n,len,tot,flag,root,rub[maxn],cnt,mode,x;
int rublish(){                      //垃圾回收,省空间
    if(tot>0)return rub[tot--];     //如果垃圾数组有不用的编号就拿来用
    return ++len;                   //没有就开一个新编号
}
void New(int val,int node,int fa){  //新建节点 val 为值, node 是编号 , fa 表示 node 的父亲
    tree[node].val=val;tree[node].fa=fa;    
    tree[node].size=tree[node].cnt=tree[node].sum=1;
    tree[node].l=tree[node].r=0;
}
int Find(int x,int node){           //寻找 x 值 的编号
    if(x<tree[node].val&&tree[node].l)return Find(x,tree[node].l);
    if(x>tree[node].val&&tree[node].r)return Find(x,tree[node].r);
    return node;
}
void update(int node,int x,int y){  //更新有修改信息的点
    if(!node)return ;   //如果跳过根了就结束
    tree[node].size+=x;
    tree[node].sum+=y;
    if((double)tree[node].size*alpha<(double)   //随便判要不要重构
    max(tree[L(node)].size,tree[R(node)].size))
    {flag=node;}                    //记录要重构的树根
    update(tree[node].fa,x,y);
}//重建树begin
void dfs(int node){                     //dfs把树拍扁成序列
    if(node==0)return;
    dfs(L(node));   //先左
    seq[++cnt]=tree[node];          //其实只需要记录部分信息,不过我太懒了
    rub[++tot]=node;                //扔进垃圾筒
    dfs(R(node));   //后右
}
int Rebuilding_Tree(int l,int r,int fa){    //把序列建为完全二叉树
    if(l>r)return 0;        //如果是空就返回
    int mid=(l+r)>>1,node=rublish();    //取一个编号
    tree[node].fa=fa;tree[node].cnt=seq[mid].cnt;tree[node].val=seq[mid].val;   //基本信息赋值
    tree[node].l=Rebuilding_Tree(l,mid-1,node);tree[node].r=Rebuilding_Tree(mid+1,r,node);  //左右儿子重建
    tree[node].sum=tree[L(node)].sum+tree[R(node)].sum+seq[mid].cnt;tree[node].size=r-l+1;  //信息更新
    return node;            //返回根
}
void rebuild(int node){                 //重建树的主函数
    cnt=0;dfs(node);
    if(node==root)root=Rebuilding_Tree(1,cnt,0);    //如果根重构就特判
    else{
        if(L(F(node))==node)tree[F(node)].l=Rebuilding_Tree(1,cnt,F(node)); //如果原来是左儿子就放左边
        else tree[F(node)].r=Rebuilding_Tree(1,cnt,F(node));            //不然就放右边
    }
}//重建树end
void insert(int x){             //插入
    if(root==0){root=rublish();New(x,root,0);return;}   //根插入特判
    int node=Find(x,root);      //找到那个点
    if(x==tree[node].val){      //如果之前就有就把数量加1
        tree[node].cnt++;
        update(node,0,1);       //更新
    }else{
        if(x<tree[node].val){   //没有就看是放左边还是右边
            tree[node].l=rublish(); //取一个编号
            New(x,tree[node].l,node);   //新建节点
        }else{
            tree[node].r=rublish(); //取一个编号
            New(x,tree[node].r,node);   //新建节点
        }
        update(node,1,1);       //更新
    }
}
void del(int x){                //删除
    int node=Find(x,root);tree[node].cnt--;     //直接找到节点然后数量减1
    update(node,0,-1);          //更新
}
int Rank(int x){                //查询排名,和BST一样
    int node=root,ans=0;
    while(tree[node].val!=x){
        if(x<tree[node].val)node=tree[node].l;  //往左找
        else ans+=tree[L(node)].sum+tree[node].cnt,node=tree[node].r;   //累加进答案往右找
        if(node==0){break;}     //找不到就退出
    }ans+=tree[L(node)].sum;    //加上左子树的数量
    return ans+1;               //加1
}
int kth(int x){                 //查询排名x的树,和BST一样
    int node=root;
    while(1){
        if(x<=tree[L(node)].sum)node=L(node);   //往左找
        else{
            x-=tree[L(node)].sum;       //减去左边的数量
            if(x<=tree[node].cnt){      //如果在该节点中
                return tree[node].val;  //返回值
            }
            x-=tree[node].cnt;          //减去自己的值
            node=R(node);               //往右节点跑
        }if(node==0)return 0;           //找不到就返回
    }
}
int pre(int x){         //查询前驱
    int node=Rank(x);node--;    //找到x的排名,减1就是前驱的排名
    return kth(node);
}
int suf(int x){         //查询后继
    int node=Rank(x);int y=Find(x,root);    //找到x的排名,加上自己的数量就是后继的排名
    if(tree[y].val==x)node+=tree[y].cnt;
    return kth(node);
}
int main(){             //主函数
    scanf("%d",&n);
    for(int i=1;i<=n;i++){flag=-1;          //重构flag赋初值
        scanf("%d%d",&mode,&x);
        if(mode==1){insert(x);}
        if(mode==2){del(x);}
        if(mode==3){printf("%d\n",Rank(x));}
        if(mode==4){printf("%d\n",kth(x));}
        if(mode==5){printf("%d\n",pre(x));}
        if(mode==6){printf("%d\n",suf(x));}
        if(flag!=-1)rebuild(flag);
    }
}

Splay

我tm终于学Splay啦

#include<bits/stdc++.h>
#define inf 2147483647
#define maxn 1000001
#define L(node) tree[node].ch[0]        //左儿子
#define R(node) tree[node].ch[1]        //右儿子
#define F(node) tree[node].fa           //父亲
#define compare(node,x) x>tree[node].val//比较x是node的左儿子还是右儿子 
using namespace std;
struct Node{
    int ch[3],fa,cnt,sum,val;
}tree[maxn];
int root,mode,x,len,n;
int read(){             //快读
    int f=0,o=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')o=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){f=f*10+ch-'0';ch=getchar();}
    return o*f;
}
void pushup(int node){          //pushup 更新数值个数
    tree[node].sum=tree[L(node)].sum+tree[R(node)].sum+tree[node].cnt;
}
void New(int node,int x,int fa){    //新建节点
    tree[node].ch[0]=tree[node].ch[1]=0;
    tree[node].fa=fa;tree[node].val=x;
    tree[node].cnt=tree[node].sum=1;
}
void ratate(int node){
    int fa=tree[node].fa;       //node节点的父亲
    int gfa=tree[fa].fa;            //node节点的爷爷
    int z=compare(fa,tree[node].val);   //判断 node是 fa 的左还是右孩子
    tree[gfa].ch[compare(gfa,tree[fa].val)]=node;   //将node变到爷爷的某个孩子上
    tree[node].fa=gfa;                  //指认父亲
    tree[fa].ch[z]=tree[node].ch[z^1];  //node原来在父亲的方向变为原node的反方向节点
    tree[tree[node].ch[z^1]].fa=fa;     //原node的反方向节点指认父亲
    tree[node].ch[z^1]=fa;              //node的反方向就是fa
    tree[fa].fa=node;                   //指认父亲
    pushup(fa);pushup(node);            //更新,因为fa在下面所以先更新fa
}

//1.node变到原来fa的位置
//2.fa变成了 node原来在fa的 相对的那个儿子
//3.fa的非node的儿子不变,node的 node原来在fa的 那个儿子不变
//4.node的 node原来在fa的 相对的 那个儿子 变成了 fa原来是node的那个儿子

void Splay(int node,int goal){      //把node旋转到goal上
    while(tree[node].fa!=goal){     //父亲是目标就可以退出了
        int fa=tree[node].fa;
        int gfa=tree[fa].fa;
        //cout<<node<<' '<<fa<<' '<<gfa<<endl;
        if(gfa!=goal){      //如果爷爷不是目标就不会执行双旋
            (compare(fa,tree[node].val))!=(compare(gfa,tree[fa].val))   //如果fa和gfa和node不在一条链上
            ?ratate(node)       //将自己旋上去
            :ratate(fa);        //不然就先旋父亲
        }
        ratate(node);       //单旋
    } if(!goal)root=node;
}
void Find(int x){       //查找x的位置,并把它Splay到根
    int node=root;if(!node)return;
    while(x!=tree[node].val){
        if(x<tree[node].val&&L(node))node=L(node);else
        if(x>tree[node].val&&R(node))node=R(node);else
        break;
    } Splay(node,0);    //旋到根
}
int Next(int x,int mode){       //查找x的 前驱 0/后继 1
    Find(x);int node=root;
    if((tree[node].val>x&&mode==1)||(tree[node].val<x&&mode==0))return node;
    node=tree[node].ch[mode];
    while(tree[node].ch[mode^1])node=tree[node].ch[mode^1];
    return node;
}
void insert(int x){             //插入
    int node=root,fa=0;
    while(tree[node].val!=x&&node){
        fa=node;                //记录父亲
        node=tree[node].ch[compare(node,x)];    //向下找点
    }
    if(node)tree[node].cnt++;   //如果原来有该节点就累加数量
    else{
        node=++len;
        if(fa)
            tree[fa].ch[compare(fa,x)]=node;    //父亲认儿子
        New(node,x,fa);         //新建节点
    }
    Splay(node,0);              //旋到根
}
void del(int x){                //删除节点
    int last=Next(x,0); //查前驱
    int nxt =Next(x,1); //查后继
    Splay(last,0);Splay(nxt,last);
    int node=tree[nxt].ch[0];
    if(tree[node].cnt>1){
        tree[node].cnt--;       //减去个数
        Splay(node,0);
    }else
    tree[nxt].ch[0]=0;          //直接删除
}
int kth(int x){                 //查询排名x的树,和BST一样
    int node=root;
    while(1){
        if(x<=tree[L(node)].sum)node=L(node);   //往左找
        else{
            x-=tree[L(node)].sum;       //减去左边的数量
            if(x<=tree[node].cnt)return tree[node].val;     //如果在该节点中,就返回值
            x-=tree[node].cnt;          //减去自己的值
            node=R(node);               //往右节点跑
        }if(node==0)return 0;           //找不到就返回
    }
}
int Rank(int x){Find(x); return tree[L(root)].sum;}     //找Rank
int pre(int x){return tree[Next(x,0)].val;}     //前驱
int suf(int x){return tree[Next(x,1)].val;}     //后继
int main(){         //主函数
    insert(-inf);insert(inf);
    n=read();
    for(int i=1;i<=n;i++){
        mode=read();x=read();
        if(mode==1)insert(x);
        if(mode==2)del(x);
        if(mode==3)printf("%d\n",Rank(x));
        if(mode==4)printf("%d\n",kth(x+1));
        if(mode==5)printf("%d\n",pre(x));
        if(mode==6)printf("%d\n",suf(x));
    }
}

猜你喜欢

转载自www.cnblogs.com/hyfhaha/p/10678344.html