平衡树——splay

洛谷【模板】普通平衡树

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff 
int n;
int tot,root;//结点总数,根
struct jade
{
	int val,fa,size,cnt;//权值,父亲,子树大小,重复次数
	int son[2];//s[0] 表示左儿子,s[1] 表示右儿子。
}t[1000005];
void init(int x,int v,int father)//创建节点后对它进行初始化
{
    t[x].cnt=t[x].size=1;
	t[x].val=v;
	t[x].fa=father;
	return ;  	
} 
void pushup(int x)//旋转后重新整合节点信息。
{
	t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+t[x].cnt;
	return ;
}
void rotate(int x)
{
	int y=t[x].fa;
	int z=t[y].fa;
	bool k=(t[y].son[1]==x);//k==0:x为y的左儿子  k==1:x为y的右儿子 
	t[z].son[t[z].son[1]==y]=x;//x代替y的位置成为z的儿子 
	t[x].fa=z;//x的父亲变为z 
	t[y].son[k]=t[x].son[k^1];//若 x为y的左儿子,则x的右儿子代替x的位置成为y的左儿子 
	                          //若 x为y的右儿子,则x的左儿子代替x的位置成为y的右儿子 
	t[t[x].son[k^1]].fa=y;//代替x的位置的儿子的父亲是y 
	t[x].son[k^1]=y;//y代替了x的儿子(那个代替了x的位置的儿子 
	t[y].fa=x;//y为x的儿子 
	pushup(y);
	pushup(x);//仿照线段树,整合应当先下后上,所以我们先 pushup(y),后 pushup(x)。(旋转后y在x下方)
	return ;
}
void splay(int x,int k)
{
	while(t[x].fa!=k)//只要还没有到 k 下方就不结束
	{
		int y=t[x].fa;
		int z=t[y].fa;
		if(z!=k)
		{
			if((t[y].son[1]==x)^(t[z].son[1]==y))
			{
				rotate(x);
			}
			else
			{
				rotate(y);
			}
		}
		rotate(x);
    }
    if(k==0)
    {
    	root=x;
	}
	return ;
}
void pre(int v)//查找数字v对应的点号 
{
	//找到v在树中的位置,并将它旋转到根
    int x=root;
    if(x==0)
    {
    	return ;
	}
	while(t[x].val!=v&&t[x].son[v>t[x].val]!=0)//大于x的权值就走右子树,否则走左子树,直到 x的权值即为v或我们要走的子树为空时停止
	{
		x=t[x].son[v>t[x].val];
	}
	splay(x,0);
	return ;
} 
void add(int v)
{
	int x=root;
	int fa=0;
	while(x!=0&&t[x].val!=v)//用查找过程找到要插入的位置,进行插入,随后将新元素旋转到根
	{
		fa=x;
		x=t[x].son[v>t[x].val];
	}
	//插入一段序列到y后,假设y的后继是z,我们会先将y旋转到根,然后再 splay(z,y) 此时只需将序列插入z的左子树即可
	if(x!=0)//这说明 v 已经在树中出现过。
	{
		t[x].cnt++;
	}
	else//新建结点。
	{
		tot++;
		x=tot;
		init(x,v,fa);//初始化。
		if(fa!=0)//u 不在根的位置上。
		{
			t[fa].son[v>t[fa].val]=x;
		}
	}
	splay(x,0);
	return ;
}
int get_k(int v,bool find)//为 0 表示找前驱,为 1 表示找后继。
{
	pre(v);
	int x=root;//首先将给定结点转到根,然后观察权值间的关系

	if(v<t[x].val&&find==1)//找后继时,根的权值大于给定值。
	{
		return x;
	}
	if(v>t[x].val&&find==0)//找前驱时,根的权值小于给定值。
	{
		return x;
	}
	x=t[x].son[find];
	while(t[x].son[find^1]!=0)//此时 u 还有儿子,往下跳。
	{
		x=t[x].son[find^1];
	}
	splay(x,0);
	return x;
}
void del(int v)
{
	//首先在树中找到要删除的元素 ,将它转到根节点并删去,这样原来的树就分裂成了两棵树。接下来将左子树中拥有最大权值的那一个元素转到根,由于它是左子树中的最大元素,所以它不存在右儿子,这样只要把原来的右子树作为它的右子树,就重新合并成了一棵树。
	int l=get_k(v,0);//查找前驱后缀时就已经转到根了,无需单独 splay。
	int r=get_k(v,1);
	splay(l,0);
	splay(r,l);
	if(t[t[r].son[0]].cnt>1)//有重复,减去重复次数即可。
	{
		t[t[r].son[0]].cnt--;
		splay(t[r].son[0],0);
	}
	else
	{
		t[r].son[0]=0;//删除左儿子。
	}
	return ;
}
int read_k(int v)
{
    pre(v);//转到根。
    return t[t[root].son[0]].size;//左子树大小
    //排名应为左子树大小加一。但由于哨兵的影响,左子树中还会有一个极小值,它让子树大小增加了一。因此直接返回 t[t[root].s[0]].size 即可。
} 
int kth(int k)
{
    int x=root;
    if(t[x].size<k)
    {
    	return -1;//整棵树都没有 k 个结点,无解。
	}
	while(1)
    {
    	if(k>t[t[x].son[0]].size+t[x].cnt)//k 大于左子树大小,答案必然在右子树。
    	{
    		k-=t[t[x].son[0]].size+t[x].cnt;//更新 k
    		x=t[x].son[1];
		}
		else
		{
			if(t[t[x].son[0]].size>=k)//k 不大于左子树大小,答案在左子树。
			{
				x=t[x].son[0];
			}
			else//答案不在左子树也不在右子树,必然就是当前结点
			{
				splay(x,0);
				return t[x].val;
			}
		}
	}
	return 0;
} 
void work()
{
	//1.插入 xx 数;
    //2.删除 xx 数(若有多个相同的数,因只删除一个);
    //3.查询 xx 数的排名(若有多个相同的数,因输出最小的排名);
    //4.查询排名为 xx 的数;
    //5.求 xx 的前趋(前趋定义为小于 xx,且最大的数);
    //6.求 xx 的后继(后继定义为大于 xx,且最小的数)。
	int opt,x;
	cin>>opt>>x;
	if(1==2)
	{
		
	}
	else if(opt==1)
	{
		add(x);
	}
	else if(opt==2)
	{
		del(x);
	}
	else if(opt==3)
	{
		add(x);
		cout<<read_k(x)<<endl;
		del(x);
	}
	else if(opt==4)
	{
		cout<<kth(x+1)<<endl;
	}
	else if(opt==5)
	{
		cout<<t[get_k(x,0)].val<<endl;
	}
	else if(opt==6)
	{
		cout<<t[get_k(x,1)].val<<endl;
	}
	return ;
}
int main()
{
	add(-inf);//插入哨兵
	add(inf);
	cin>>n;
	while(n--)
	{
		work();
	}
    return 0;
} 

D3906-ourstar的spaly
樱雪喵的spaly
XichenOC的spaly

洛谷【模板】文艺平衡树

#include<bits/stdc++.h>
using namespace std;
struct jade
{
	int son[2],size,fa,val,tag,cnt;
}t[100010];
int root,tot;
int inf=100000089;
int a[100010];
void pushup(int x)
{
    if(x)
	{
	    t[x].size=t[x].cnt+t[t[x].son[0]].size+t[t[x].son[1]].size;	
    }
    return ;
} 
void pushdown(int x)
{
	if(x&&t[x].tag)
	{
		t[t[x].son[1]].tag^=1;
		t[t[x].son[0]].tag^=1;
		swap(t[x].son[1],t[x].son[0]);
		t[x].tag=0;
	}
}
void rotate(int x)
{
    int y=t[x].fa;
	int z=t[y].fa;
	pushdown(x);
	pushdown(y);
	bool k=(t[y].son[1]==x);
	t[z].son[t[z].son[1]==y]=x;
	t[x].fa=z;
	t[y].son[k]=t[x].son[k^1];
	t[t[x].son[k^1]].fa=y;
	t[x].son[k^1]=y;
	t[y].fa=x;
	pushup(y);
	pushup(x);	
	return ;
} 
void splay(int x,int k)
{
	for(int i;(i=t[x].fa)!=k;rotate(x))
	{
		if(t[i].fa!=k)
		{
			if((t[t[x].fa].son[1]==x)^(t[t[i].fa].son[1]==i))
			{
				rotate(x);
			}
			else
			{
				rotate(i);
			}
		}
	}
	if(k==0)
	{
		root=x;
	}
} 
int build_tree(int l,int r,int fa)
{
    if(l>r)
	{
		return 0;
	}
	int mid=(l+r)>>1;
	tot++;
	int x=tot;
	t[x].fa=fa;
	t[x].son[0]=t[x].son[1]=0;
	t[x].cnt++;
	t[x].val=a[mid];
	t[x].size++;
	t[x].son[0]=build_tree(l,mid-1,x);
	t[x].son[1]=build_tree(mid+1,r,x);
	pushup(x);
	return x; 
}
int find(int x)
{
    int y=root;
	while(1)
	{
		pushdown(y);
		if(x>t[t[y].son[0]].size)
    	{
    		x-=t[t[y].son[0]].size+1;
            if(!x) 
            {
            	return y;
			}
    		y=t[y].son[1];
		}
		else
		{
			y=t[y].son[0];
		}
	}	
} 
void reverse(int x,int y)
{
	int l=x-1,r=y+1;
	l=find(l),r=find(r);
	splay(l,0);
	splay(r,l);
	int pos=t[root].son[1];
	pos=t[pos].son[0];
	t[pos].tag^=1;
} 
void dfs(int x)
{
    pushdown(x);
	if(t[x].son[0])
	{
		dfs(t[x].son[0]);
	}
	if(t[x].val!=-inf&&t[x].val!=inf)
	{
		cout<<t[x].val<<" ";
	}
	if(t[x].son[1])
	{
		dfs(t[x].son[1]);
	}	
} 
int main()
{
	int n,m,x,y;
	cin>>n>>m;
	a[1]=-inf;
	a[n+2]=inf;
	for(int i=1;i<=n;i++)
	{
		a[i+1]=i;
	}
	root=build_tree(1,n+2,0);
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		reverse(x+1,y+1);
	}
	dfs(root);
	return 0;                                      
}

皎月半洒花的splay

posted @ 2025-07-10 19:06  BIxuan—玉寻  阅读(14)  评论(0)    收藏  举报