平衡树 区间树 学习

前记

把之前学的平衡树都写一下,最近更新: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));
	}
}
posted @ 2019-04-09 17:20  Hastieyua  阅读(316)  评论(0编辑  收藏  举报