首页 > 其他分享 >笛卡尔树

笛卡尔树

时间:2024-09-11 15:36:14浏览次数:8  
标签:右链 笛卡尔 int top 二叉 插入 stk

解决的问题

有 \(n\) 个值,每个值有两个信息 \((a_i, b_i)\)。你需要在这 \(n\) 个值间连边并形成一棵二叉树,使得:

  • 每个点的 \(a_i\) 满足二叉搜索树的性质。即对于所有 \(v \in \text{subtree}_{lson}\) 都有 \(a_v \le a_u\),对于所有 \(v \in \text{subtree}_{rson}\) 都有 \(a_v > a_u\)。
  • 每个点的 \(b_i\) 满足小根堆的性质。即对于所有 \(v \in \text{subtree}_u\) 都有 \(a_v \ge a_u\)。

例如当 \(a = \{1,2,3,4,5\},b = \{4, 1, 3, 2, 5\}\) 时

算法

首先我们将所有值按照 \(a\) 升序排序。然后从左往右向树中插入。显然当一个值被插入时它的 \(a\) 一定是最大的。

此时我们默认插入新值之前的二叉树是合法的。

我们回忆一颗二叉搜索树中的最大值是什么。因为一个点的右儿子的权值一定比自己大,所以我们从根开始不断往右走,走不动时所在的点就是二叉搜索树中的最大值。例如在上左图中最大值 \(5\) 就是从根一直走右儿子得到的。

我们定义从根开始,如果一直可以就走到当前点的右儿子,这个过程中经过点构成的序列为右链。例如上左图中右链为 \(2,4,5\)。那么二叉搜索树上的最大值就是这棵树的右链的最后一个元素。

回到原问题。我们希望在新值的 \(a\) 最大,也就是成为树上右链的末端。

但是直接将其设为当前右链末端的右儿子肯定不行。因为这可能导致小根堆的条件不满足。我们考虑调整颗树的形态。

具体的,因为插入新值之前这棵树的形态是正确的,所以右链上的点的 \(b\) 权值一定随深度递增(小根堆)。例如上右图中的 \(1,2,5\)。所以将新值插入后右链上 \(b\) 的单调性必须仍保持。

所以如果我们要插入值 \((6, 4)\):

  • 右树中 \(4\) 的位置必须要在 \(2,5\) 之间。这样能保证 \(b\) 的小根堆性质。
  • 左树中 \(6\) 的位置必须在右链末端。这样能保证 \(a\) 的二叉搜索树性质。

最好的调整方法是这样:

即 \(rson((4,2)) \gets (6,4)\),\(lson((6,4)) \gets (5,5)\)。其余点的左右儿子均不改动。

实现上,我们维护一个栈存储当前树上的右链。栈顶元素为右链末端,栈底元素为根。每次插入一个值 \((a_i,b_i)\) 时,我们找到当前栈内最靠上的一个点 \(j\) 满足 \(b_j > b_i\),并将 \(j\) 及以上的点全部弹栈。令 \(k\) 表示操作后的新栈顶,然后执行 \(rson(k) \gets i,lson(i) \gets j\) 即可。

建出来的树即笛卡尔树。

P5854 【模板】笛卡尔树 的代码如下。因为这道题的二叉搜索树权值就是下标,所以不用排序,直接从左往右插入即可。

int n, a[N];
int l[N], r[N];		// 左右儿子
int stk[N], top;	// 右链

cin >> n;
for (int i = 1; i <= n; ++ i ) {
	cin >> a[i];
	
	int k = top;
	while (top && a[stk[top]] > a[i]) top -- ;
	if (top) r[stk[top]] = i;
	if (top < k) l[i] = stk[top + 1];
	
	stk[ ++ top] = i;
}

应用技巧

  • 以 \(u\) 为根的子树对应到原序列上是一段区间,且根节点是这段区间的最小/大值(取决于小根堆还是大根堆)。

  • 将笛卡尔树中序遍历(左根右)能得到原序列。

标签:右链,笛卡尔,int,top,二叉,插入,stk
From: https://www.cnblogs.com/2huk/p/18408317

相关文章

  • 笛卡尔树
    讲义 第1题   笛卡尔树一、定义与性质    笛卡尔树是一种特殊的二叉树数据结构,每个节点都由一对键值构成,即(k,w),其中k满足二叉搜索树的性质,而w满足堆的性质。具体来说:    二叉搜索树性质:      对于任意节点x,其左子树中的所有键值k都小于x......
  • 【数据结构】【模板】笛卡尔树
    笛卡尔树定义笛卡尔树每个节点有两种属性,一种是键值,一种是优先级。一般将位置作为键值,维护BST的性质,这样其中序遍历一定为\(1~n\)。一般将数值看作优先级,维护堆的性质。构建思路维护一个单调栈,表示现在的右链长度。我们将数组从前往后插入笛卡尔树。对于第\(i\)个......
  • 【Python】笛卡尔积 intertools.product()
    一、题目Thistoolcomputesthecartesianproductofinputiterables.Itisequivalenttonestedfor-loops.Forexample,product(A,B)returnsthesameas((x,y)forxinAfroyinB).SampleCodefromitertoolsimportproductprint(list(product([1,2,3],......
  • 理解笛卡尔积在数据库查询中的实际应用与优化
    理解笛卡尔积在数据库查询中的实际应用与优化大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!笛卡尔积是关系数据库查询中的一个基础概念,它描述了两个表之间所有可能的行组合。尽管它在某些情况下是必要的,但它也可能导致性能问题。本文将详细介绍笛卡......
  • 笛卡尔坐标转经纬度坐标
    functionfromCartesian(cartesian){constoneOverRadii={x:1.0/6378137.0,y:1.0/6378137.0,z:1.0/6356752.3142451793};constoneOverRadiiSquared={x:1.0/(6378137.0*6378137.0),y:1.0/(6378137.0*6378137.0),......
  • 经纬度坐标转笛卡尔坐标
    functionfromDegrees(longitude,latitude,height=0.0){longitude=(longitude*Math.PI)/180.0;latitude=(latitude*Math.PI)/180.0;constradiiSquared={x:6378137.0*6378137.0,y:6378137.0*6378137.0,z:6356752.31424517......
  • 笛卡尔树
    笛卡尔树:笛卡尔树是关于多个二元组\((k_i,w_i)\)的一棵树,使其所有\(k\)值满足二叉搜索树的性质,且所有\(w\)值都满足小根堆的性质。笛卡尔树有一些关于区间最值的美好性质,常常用于处理关于区间最值的问题。构建方法:在构建时,对于右链上的元素,自底向上一定是\(w\)值由小......
  • 笛卡尔树
    \(\texttt{0x00}\):前置芝士二叉搜索树堆单调栈\(\texttt{0x01}\):概念笛卡尔树是一种二叉树,每一个结点由一个键值二元组\((k,w)\)构成。要求\(k\)满足二叉搜索树的性质(左小右大),而\(w\)满足堆的性质(大根堆或小根堆)。q1:这么一看,Treap不也是笛卡尔树?a1:正确的。一个有......
  • 仅产生 2D 笛卡尔积的上三角形
    我知道如何使用itertools.productIn[19]:fromitertoolsimportproduct...:...:abcd=product('abcd','abcd')...:foriinrange(4):...:print(''.join(repr(t)for_,tinzip(range(4),abcd)))......
  • Franka Robot 如何理解机器人的笛卡尔阻抗运动
    在笛卡尔阻抗模式下,用手将机器人移动到一个新位置后,机器人的行为取决于其控制参数(刚度、阻尼、质量)的设定和外部力的作用。当你将机器人移动到一个新位置并释放它时,以下是可能的情况:高刚度情况下如果机器人的刚度(Stiffness)参数设置较高,意味着机器人对位置偏差有很强的恢复力。当......