对于平衡树的新理解。。。(最弱的蒟蒻出品)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 1000001
using namespace std;

int f[maxn],ch[maxn][2],num[maxn],cnt[maxn],size[maxn];
int tree_size,root,n,p,t,x;
inline void clear(int x){
    ch[x][0]=ch[x][1]=f[x]=cnt[x]=num[x]=size[x]=0;
}//将这个节点全部清空,清空即将所有信息初始化为0 

inline int get(int x){
    return ch[f[x]][1]==x;
}//每次判断是在左儿子还是右儿子,并且巧妙地运用了。。。(ch[f[x]][1]==x返回值是1,那么就是右儿子!!!) 

inline void update(int x){//更新子树的大小 
    if (x){
        size[x]=cnt[x];
        if (ch[x][0]) size[x]+=size[ch[x][0]];
        if (ch[x][1]) size[x]+=size[ch[x][1]];
    }
}

inline void rotate(int x){
    int y=f[x];
    int z=f[y];
    int tmp=get(x);
    ch[y][tmp]=ch[x][!tmp];//y在进行一次旋转之后必然会连接在(与原先接在z方向上不同的)的方向位置 
    f[ch[y][tmp]]=y;//将原先放置在与(y连接z相反方向)的tmp(即相反方向的儿子)连在y上(数学归纳法总结。。。。) 
    ch[x][!tmp]=y;
    f[y]=x;
    f[x]=z;
    if (z) ch[z][ch[z][1]==y]=x;//如果其祖父节点是存在的话,那就将原来y的位置换为x的位置。。。。 
    update(y),update(x);//每次将子树的大小更新一次 
}

inline void splay(int x){
    for (int fa; (fa=f[x]); rotate(x))
        if (f[fa]) rotate(((get(x)==get(fa))?fa:x));
    root=x; 
    //每次执行的同时,判断是链式还是拐弯式的,并对其进行rotate操作。。。 
}

inline void insert(int x){
    if (root==0) {
    tree_size++; 
    ch[tree_size][0]=ch[tree_size][1]=f[tree_size]=0; 
    root=tree_size; 
    size[tree_size]=cnt[tree_size]=1; 
    num[tree_size]=x; 
    return;
    }
    //还未开始建子树的判断
     
    int now=root,father=0;
    while (1){
        if (x==num[now]){
            cnt[now]++;
            update(now);//更新当前节点信息 
            update(father);//由于当前节点的信息和父亲节点的信息是紧密相关的,所以需要更新父节点信息 
            splay(now);
            break;//如果有重复现象,那么就将计数器++,并且将其再进行一次玄学伸展。。。 
        }
        //如果没有重复。。。 
        father=now;
        now=ch[now][num[now]<x];//如果没能找到其位置,就继续根据其权值的大小下放该数
        if (now==0){//如果找不到子节点。。。那么就意味着已经找到了该值的归宿(有点怪) 
            tree_size++;//将它放置到树编号的最末 
            ch[tree_size][0]=ch[tree_size][1]=0;//初始化它的子节点 
            f[tree_size]=father;//并将其接到父节点上 
            size[tree_size]=cnt[tree_size]=1;//更新它所包含的子树大小以及计数值 
            ch[father][num[father]<x]=tree_size;//更新其父节点
            num[tree_size]=x;
            update(father);
            splay(tree_size);
            break;
        }
    }
}

inline int findx(int x){//查找序号为x的节点 
    int now=root;
    while (1){
        if (x<=size[ch[now][0]]) now=ch[now][0];//如果在左儿子,就转向左儿子 
        else{
        int tmp=size[ch[now][0]]+cnt[now];//转向右儿子。。。
        if(x<=tmp) return num[now];
        x-=tmp; now=ch[now][1];
       }   
    }
}

inline int find(int x){//查找值是x的序号 
    int now=root,ans=0;
    while (1){
        if (x<num[now]) now=ch[now][0];
        else{ 
            ans+=size[ch[now][0]];//累加树的节点个数 
            if (x==num[now]){
                splay(now); return ans+1;
            }
             ans+=cnt[now];
            now=ch[now][1];//向右扩展 
        }
    }
}

inline int pre(){int now=ch[root][0]; while (ch[now][1]) now=ch[now][1]; return now;}

inline int next(){int now=ch[root][1]; while (ch[now][0]) now=ch[now][0]; return now;}

inline void del(int x){
    find(x);//将x变为根节点!!
    if (cnt[root]>1){ cnt[root]--; update(root); return;}//如果有重复直接一步更新 
    if (!ch[root][0] && !ch[root][1]) {clear(root); root=0; return;}//如果孤苦伶仃,就直接删除。。。 
        if (!ch[root][0]){
            int y=root;
            root=ch[root][1]; 
            f[root]=0;//已经在根节点,所以f应赋成0
            clear(y); return;
        }
        else if (!ch[root][1]){
            int y=root;
            root=ch[root][0];
            f[root]=0;
            clear(y);
            return;
        }
        //将左边的最大移至根节点 
        int lef=pre(),y=root;
        splay(lef);
        ch[root][1]=ch[y][1];
        f[ch[y][1]]=root;
        clear(y); 
        update(root);
}
int main(){
    scanf("%d",&n);
    for (int i=1; i<=n; i++){
        scanf("%d%d",&p,&x);
        switch(p){
        case 1:insert(x); break;
        case 2:del(x); break;
        case 3:printf("%d\n",find(x)); break;
        case 4:printf("%d\n",findx(x)); break;
        case 5:insert(x); printf("%d\n",num[pre()]); del(x); break;
        case 6:{insert(x); 
        printf("%d\n",num[next()]); 
        del(x); 
        break;}
    }}
}

 

posted @ 2017-08-25 14:31  最弱的蒟蒻  阅读(191)  评论(0)    收藏  举报