首页 > 其他分享 >平衡树

平衡树

时间:2024-11-02 17:09:35浏览次数:2  
标签:int siz pos son fa 平衡 now

Splay

技巧/记忆点:

1、Rotate()中,使用变量记录位置关系和下标;

2、Find()(找元素\(x\)所在位置)减少重复代码;

3、求前驱/后继时先把这个数插进去再删掉;

4、Splay()父子同侧先翻父亲,再翻儿子,否则翻两边儿子;

5、siz[]在Splay()前先Pushup()到树根,这样在Rotate()维护会轻松一点;

6、Delete()先旋删点至根,删掉,再把左子树的最大值旋至根,连右子树即可;

代码

#include<iostream>
#define dir(x) son[fa[x]][1]==x
using namespace std;
const int MAXN=2e5+100;
int n;
class Balance_Tree {
	private:
		int a[MAXN],fa[MAXN],son[MAXN][2],cnt[MAXN],siz[MAXN],rt,tot;
		void Pushup(int x) {
			for(;x;x=fa[x]) siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];
		}
		void Rotate(int x) {
			bool dx=dir(x),dy=dir(fa[x]);
			int y=fa[x],z=fa[fa[x]];
			siz[y]=cnt[y]+siz[son[y][!dx]]+siz[son[x][!dx]];
			siz[x]=siz[x]+siz[son[y][!dx]]+cnt[y];
			fa[x]=z;
			son[z][dy]=x;
			fa[son[x][!dx]]=y;
			son[y][dx]=son[x][!dx];
			fa[y]=x;
			son[x][!dx]=y;
		}
		void Splay(int x,int goal) {
			for(;fa[x]!=goal;Rotate(x)) {
				if(fa[fa[x]]) {
					if(dir(x)==dir(fa[x])) Rotate(fa[x]);
					else Rotate(x);
				}
			}
			if(!goal) rt=x;
		}
	public:
		int Find(int x) {
			int pos=rt,pre=0;
			while(pos&&a[pos]!=x) 
				pre=pos,pos=son[pos][a[pos]<x];
			return (pos?pos:pre);
		}
		void Insert(int x) {
			if(!rt) {
				a[++tot]=x;
				cnt[tot]=siz[tot]=1;
				rt=tot;
				return;
			}
			int pos=Find(x);
			if(a[pos]==x) ++cnt[pos],++siz[pos]; 
			else {
				son[pos][a[pos]<x]=++tot;
				fa[tot]=pos;
				a[tot]=x;
				siz[tot]=cnt[tot]=1;
				pos=tot;
			}
			Pushup(pos);
			Splay(pos,0);
		}
		void Delete(int x) {
			int pos=Find(x);
			Splay(pos,0);
			--cnt[pos]; --siz[pos];
			if(!cnt[pos]) {
				fa[son[pos][0]]=fa[son[pos][1]]=0;
				if(son[pos][0]==0||son[pos][1]==0) {
					rt=son[pos][son[pos][0]==0];
					return;
				}
				rt=son[pos][0];
				Splay(Find(1e9),0);
				son[rt][1]=son[pos][1];
				fa[son[pos][1]]=rt;
				siz[rt]+=siz[son[pos][1]];
			}
		}
		int Getrank(int x) {
			Splay(Find(x),0);
			return siz[son[rt][0]]+1;
		}
		int Getk_th(int x) {
			int pos=rt;
			while(true) {
				if(siz[son[pos][0]]>=x) pos=son[pos][0];
				else if(siz[son[pos][0]]+cnt[pos]>=x) return a[pos];
				else x-=(siz[son[pos][0]]+cnt[pos]),pos=son[pos][1];
			}
		}
		int Getpre(int x) {
			Insert(x);
			int pos=rt,pre=0;
			while(pos) pre=pos,pos=son[pos][a[pos]<x];
			Delete(x);
			return a[pre];
		}
		int Getnxt(int x) {
			Insert(x);
			int pos=rt,pre=0;
			while(pos) pre=pos,pos=son[pos][a[pos]<=x];
			Delete(x);
			return a[pre];
		}
}tr;
inline int read() {
	int x=0,op=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {
		if(ch=='-') op=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=(x<<3)+(x<<1)+(ch^'0');
		ch=getchar();
	}
	return x*op;
}
int main() {
	n=read();
	for(int i=1;i<=n;i++) {
		int op=read(),x=read();
		if(op==1) tr.Insert(x);
		if(op==2) tr.Delete(x);
		if(op==3) cout<<tr.Getrank(x)<<endl;
		if(op==4) cout<<tr.Getk_th(x)<<endl;
		if(op==5) cout<<tr.Getpre(x)<<endl;
		if(op==6) cout<<tr.Getnxt(x)<<endl;
	}
	return 0;
} 

文艺平衡树

题目链接

维护区间翻转操作

即对于一棵树的每个节点,都交换左右儿子

只需把树转成这个样子,然后打标记即可

正确性

乍一看存在左右儿子交换,二叉搜索树的性质会被破坏,但是考虑到所有数加进来后,它们的值就用不到了

构造该结构:将第\(l-1\)个和第\(r+1\)个数转上来即可,用\(siz[]\)维护

因此用\(Getk\_th()\)即可,权值用不到,所以破坏了也不影响

还有一个问题,就是构造结构时有Splay操作,是否会因为标记而错误

这个是不会的,在\(Getk\_th()\)中已经完成了\(rt\to pos\)这条路径的Pushdown,而Splay恰就只在这条链上转,所以该链已经正确,至于别的点,无所谓,旋转不会对它们造成影响

核心代码

void Pushdown(int x) {
	if(tag[x]) {
		swap(son[x][0],son[x][1]);
		tag[son[x][0]]^=tag[x];
		tag[son[x][1]]^=tag[x];
		tag[x]=0;
	}
}
int Getk_th(int x) {
	int now=rt;
	while(true) {
		Pushdown(now);
		if(siz[son[now][0]]==x-1) return now;
		else if(siz[son[now][0]]>x-1) now=son[now][0];
		else x-=siz[now]-siz[son[now][1]],now=son[now][1];
	}
}
void Reverse(int l,int r) {
	Splay(Getk_th(l-1),0);
	Splay(Getk_th(r+1),rt);
	tag[son[son[rt][1]][0]]^=1;
}

标签:int,siz,pos,son,fa,平衡,now
From: https://www.cnblogs.com/zhone-lb/p/18522222

相关文章

  • 动态动态规划 & 全局平衡二叉树 小记
    估计这几天是正式学习ddp,所以特写笔记。DDP简介是这样一类技巧,利用广义的矩阵乘法实现单点修改权值,动态查询某个点的DP值关于矩阵乘法,广义矩阵乘法其核心思想是利用矩阵乘法具有结合律(可以使用数据结构维护)的优势序列上的Ddp先看一个例子:最大子段和,显然我们有\(f_......
  • 洛谷题单指南-字符串-P3369 【模板】普通平衡树
    原题链接:https://www.luogu.com.cn/problem/P3369题意解读:平衡树的基本操作,模版题。解题思路:1、二叉搜索树-BST二叉搜索树满足这样的性质:每一个节点的权值大于它的左儿子,小于它的右儿子。对BST进行中序遍历,将得到一个从小到大的有序序列,因此BST是为了维护一个有序序列的动态......
  • 代码随想录算法训练营第十三天| 110.平衡二叉树、257. 二叉树的所有路径、404.左叶子
    110.平衡二叉树题目链接:.-力扣(LeetCode)文章链接:代码随想录视频链接:后序遍历求高度,高度判断是否平衡|LeetCode:110.平衡二叉树_哔哩哔哩_bilibili《代码随想录》算法公开课开讲啦!快来打卡!本期视频的文字讲解版在「代码随想录」刷题网站:programmercarl.com,这里刷题顺序,详......
  • 代码复用:DDD视角下的平衡艺术
    代码复用:DDD视角下的平衡艺术https://mp.weixin.qq.com/s/5gIBJByRZfNPbh6yjAvj9w代码复用:DDD视角下的平衡艺术原创 杜沁园(悬衡) 阿里技术 2024年10月11日08:31 浙江  这是2024年的第76篇文章(本文阅读时间:15分钟)01引言刚工作时,代码写得不太好,师兄每次CR代......
  • 程序化交易策略里,风险管理和心态控制怎样平衡?
    Python股票接口实现查询账户,提交订单,自动交易(1)Python股票程序交易接口查账,提交订单,自动交易(2)股票量化,Python炒股,CSDN交流社区>>>风险识别与评估程序化交易面临多种风险,包括市场风险、技术风险等。市场风险源于市场波动,价格变动可能使策略失效。技术风险则与交易系统......
  • 【C++】—— priority_queue :平衡效率与秩序的算法利器
    去感受一棵草、一缕风、一场日落,去重新触摸真正的生活。——高盛元目录1、优先级队列1.1什么是优先级队列1.2 priority_queue的使用1.3仿函数2、priority_queue的模拟实现2.1整体框架接口2.2插入&&向上调整2.2删除&&向下调整2.3其他接口2.4优先级队列的应用......
  • 3.AVL平衡树
    AVL平衡树特征:AVL树既是二叉搜索树,也是平衡二叉树,同时满足这两类二叉树的所有性质AVL树是一种平衡二叉搜索树属性:节点高度节点平衡因子:节点左子树的高度减去右子树的高度,空节点的平衡因子为0AVL树旋转:作用:AVL树的特点在于“旋转”操作,它能够在不影响二叉树的中......
  • 产品经理和项目经理的冲突,怎么解决两个角色的平衡
    产品经理(ProductManager)与项目经理(ProjectManager)之间的冲突通常根源于职责划分的不清晰、目标差异性、资源分配和优先顺序的不一致。要解决两个角色的平衡,关键在于明确角色边界、建立共同的目标、优化沟通流程、以及协同合作机制的设计。特别是角色边界的明确,可以有效避免工......
  • (七)阶段性成果-simulink实现小车倒立摆,使用LQR控制,摆杆初始角度在平衡位置附近。
    效果如下图所示:共有两个.m文件第一个:start.m%%参数设置globalMmlgkM=2;m=0.5;l=0.3;g=9.81;wheel_damping=1e-5;joint_damping=1e-5;x_0=0;y_0=0.125;q_0=10;%系统矩阵A和BA=[0010;0001;0(m*g)/M00;0(M+m)*g......
  • ReactOS系统中平衡二叉树,在一个空间中寻找与给定地址范围重合或部分重合的(已分配)区间
    在一个空间中寻找与给定地址范围重合或部分重合的(已分配)区间PMEMORY_AREANTAPIMmLocateMemoryAreaByRegion(PMADDRESS_SPACEAddressSpace,PVOIDAddress,ULONG_PTRLength);MmLocateMemoryAreaByRegion/******************************************************......