ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

神秘数据结构:笛卡尔树

2021-07-28 23:33:52  阅读:694  来源: 互联网

标签:神秘 log 笛卡尔 BST 最小值 数据结构 我们 性质


目录

这是一种大家都听过名字但都没做过多少例题的奇怪数据结构。

但是今天研究一下NOI大纲,它好像要靠,算了,整吧

和其它维护信息的数据结构不太相同的是,它更多的是去支持数数,或者是决策,之类的。

笛卡尔树是啥

这是一种数据结构,可以把一堆形如 \((x_i,y_i)\) 的点对放到二叉树上,使得:

  • 只看 \(x\),树的中序遍历有序,即满足二叉搜索树(Binary Search Tree, BST)性质(左小右大)
  • 只看 \(y\),这是一个二叉堆,大根/小根

它的性质非常优秀,可以支持一些跟最大值有关的问题,或者是插入删除之类的问题(记录插入删除时间)

咋建

以小根为例,大根就反一下。

我们先把 \(x\) 排一下序。

法1

考虑树的根。由堆的性质,这是原序列的最小值。由BST性质,我们可以递归解决两边。

然后就每次把最小值提起来变成根,左右分别处理接在下面就行了。这样就是 \(O(n^2)\) 的,用线段树优化一下能做到 \(O(n\log n)\)

尽管这个方法没有下一个方法快,但它能帮助我们理解笛卡尔树的性质。

法2

线性!(如果保证 \(x\) 有序)

考虑增量法,每次枚举一个 \(i\) 看看怎么把它加进来

为了满足BST性质,我们的第一反应是不断的走右儿子(即,右链),然后把它接在这条链底部的右儿子。

实际上我们再想一下,我们其实可以在右链上找一个地方把它“插入”进来,同样满足BST性质。如下图:

image-20210728222022416

即,对于原树右链上 \(u\) 到 \(v\) 的一条边,令 \(u\) 的右儿子为 \(i\),然后 \(i\) 的左儿子再接到 \(v\),这样就实现了把 \(i\) “插入” 到右链。

由于(小根)堆性质,任意一条向下的链都是递增的。我们要把当前的点 \(i\) 插入进来,就要找一个 “中间位置”,即,\(u\) 到 \(v\) 的边,满足:\(a_u<a_i\) 而 \(a_i>a_v\)。此时用上述的 “插入” 方法把 \(i\) 插进来,容易发现,即满足了BST性质,又满足了BST性质。

照理来说找这个位置应该用二分法,然而,我们可以用一个单调栈来暴力维护,由于每个数只会进出一次,所以总复杂度是线性的。

还有一个细节注意,就是 \(i\) 一来直接变成当前最小值,反 客 为 主,此时不但要清掉链,还要把根设置成 \(i\)。

代码(洛谷板子)

性质 / 事实

(以小根为例)

  1. 以 \(u\) 为根的子树是一段连续的区间 (由BST性质),且 \(u\) 是这段区间的最小值,且不能再向两端延伸使得最小值不变(即,这一段区间是极长的)
  2. 在 \(u\) 左右子树里任选两个点,两点间的区间最小值必定是 \(y_u\)
  3. \(a,b\) 间的区间最小值为:\(y_{LCA(a,b)}\)
  4. 若 \(y\) 是个随机排列,\(x\) 是 \(1,2,3...n\),则树高期望为 \(\log\),具体多少后面说
  5. Treap是一颗笛卡尔树,它依靠性质4确保复杂度

来点题!

上面提到,笛卡尔树可以有效的解决一些和最大/最小值有关的问题,或者是和插入删除有关的问题

经典题:柱状图最大子矩阵

直接形式化描述吧,给一个数组 \(h\),求

\(max\{min(h_{l...r})\times (r-l+1\},1\le l\le r\le n\)

我们想到可以钦点最小值,然后看最小值等于它的最长区间。

区间限制在下标上,而最大值的限制在 \(h\) 上。容易想到,下标第一维,\(h\) 值第二维,来一颗笛卡尔树。

由性质1,我们可以枚举笛卡尔树上的节点,然后最长区间就是子树大小,更新一下最大值即可。

复杂度:\(O(n)\)

当然,这题也可以直接单调栈做,本质是差不多的

TJOI2011 树的序

首先有一个明显的贪心:我们先把BST搞出来,然后在BST上贪心跑:先走小儿子,后走大儿子。很显然这样的贪心是对的,因为先走大儿子,在这一位上就输了,肯定不优。

问题在于如何建BST。更明确的说,\(a_i\) 的 BST。

那我们建出来的树肯定对于 \(a\) 满足 BST 性质了。然后再想到,我们每次插一个新数,都会插在下面。所以这颗树上,下面编号大于上面。

所以对于编号来说,这颗树满足堆性质。

好,一个BST性质,一个堆性质,笛卡尔树,没了。即,以 \((a_i,i)\) 建一颗笛卡尔树,就是 \(a_i\) 的 BST 了。

由于 \(a\) 无序,需要先把它排一下序,复杂度就是 \(\log\) 了。

当然,这个 \(\log\) 的常数小的可以,因为 std::sort 非常快!

总结:若发现了一个BST性质,一个堆性质,啪的一下想到笛卡尔树

SPOJ PERIODNI

bzoj2616

我们注意到,对于一段棋盘,真正有限制条件的只有下面那一段。对于上面,因为没法跨过来,所以可以随便放,无影响。

我们的问题又和最小值有关了,所以考虑笛卡尔树,小根的。

建出来树之后直接在树上考虑问题。设当前点是 \(u\)。对于它左右两颗子树对应区间里的棋盘,我们划分成两块:最小值上面的那一块,称作 \(A\);大家共有的最小值那一块,称作 \(B\)。如下图,绿色线上面就是 \(A\),下面就是 \(B\)。

image-20210728224805612

对于 \(B\),问题相当于我们要选若干个位置,使得行列均不同。用组合数选出行与列都是啥,再配对,就行了。

而对于 \(A\),问题就麻烦在如何把下面这一块去掉。经过一番思考,得到一个神秘方法:直接记 \(f(u,x)\) 表示,\(u\) 子树里,把 \(u\) 父亲的那一段长度切掉,然后放 \(x\) 个车车的方案数。

那对于当前的 \(u\),我们直接把左右儿子的 \(f\) 做一个卷积(这里可以暴力卷,因为瓶颈不在这),就可以得到在 \(A\) 部分里选若干个的方案数了。

对于 \(B\),我们需要选若干个行,列出来。假设当前有 \(H\) 行,\(W\) 列供选择。容易发现,\(H=a_u-a_{fa}\),\(W=size(u)\),即子树大小。

假设我们要求 \(f(u,i)\),即一共选 \(i\) 个;在 \(B\) 部分选择 \(j\) 个。此时 \(A\) 部分选择 \(i-j\) 个,尽管不占据 \(B\) 部分的行,但占据掉了列。于是 \(B\) 部分的方案数为:

\[\binom{H}{j}\binom{W-(i-j)}{j}\times j! \]

其中 \(j!\) 是选出来的行与列配对的方案数。

然后我们再把 \(A,B\) 部分的方案数卷起来,就可以得到 \(f(u,0...k)\) 了。

代码

agc028B Removing Blocks

首先我们可以把它看成是,均匀随机一个删除顺序,求代价的期望,乘一个 \(n!\)

我们发现,每次删一个位置,然后两边分开搞,和笛卡尔树建树过程非常的类似。把每个点的删除时间搞出来,删一个点就提它做根,然后左右两边接过来,我们发现,它是一个笛卡尔树。其中,下标满足BST性质,删除时间满足小根堆性质。

一个位置的贡献就是它在笛卡尔树上的点深度 (即,到根路径上多少个点)。我们相当于求它的期望深度,乘以它的权值,加起来,就是代价的期望(由期望线性性)

现在问题变成如何求随机排列构成笛卡尔树的期望深度。

\(E(dep_i)=\sum\limits_{j} P(j\in anc(i))\),\(anc(u)\) 表示 \(u\) 的祖先。

问题又变成,\(j\) 是 \(i\) 祖先的概率。不妨令 \(j<i\),\(j>i\) 同理。

想象一下笛卡尔树的结构,如果 \(j\) 要是 \(i\) 的祖先,那 \([j,i]\) 这一段里面,\(j\) 得是最小值——要不然切在中间就把 \(i,j\) 分在两颗子树里了。

现在问题又变成,随机一个排列,区间 \([l,r]\) 中 \(l\) 位置是最小值的概率。

首先我们先选 \(r-l+1\) 个位置放在区间里,然后令 \(n-(r-l+1)\) 个位置随便排, \(l\) 位置放最小值,\((r-l+1)-1\) 个位置再随便排,最后除以 \(n!\) 就行了。推一波式子发现一堆东西都抵消了,最后概率为 \(\dfrac{1}{r-l+1}\)。应该有其它妙妙理解,但是我只会瞎几把推。

\(j>i\) 同理。最后搞出来我们发现这是一个调和级数求和。设调和级数 \(H(n)=\sum\limits_{i=1}^{n} \dfrac{1}{i}\)

\(E(dep_i)=H(i)+H(n-i+1)-1\)

然后再按上述做一波就好了。

同时,由于 \(H(n)\) 和 \(\log n\) 是同阶的,我们也证明了随机排列的笛卡尔树的深度,期望是 \(\log\) 的。

代码

笛卡尔树上启发式合并/分裂

启发式合并大家熟悉,启发式分裂的意思就是,我枚举一个点 \(u\),算跨过 \(u\) 的情况,然后两边分别处理。对于计算跨过 \(u\) 的情况,我看左右哪个子树小,我就按这个子树作为枚举的标准,另一颗子树里块速的做。和启发式合并类似,它的复杂度也是多一个 \(\log\)。

例题:hdu6701,洛谷4755

都是启发式分裂,统计一下跨过中间的答案,两边递归做就行。

hdu那个比较傻逼,而洛谷的那个还需要小小的去一下重。

代码:

hdu题

咕咕题

标签:神秘,log,笛卡尔,BST,最小值,数据结构,我们,性质
来源: https://www.cnblogs.com/LightningUZ/p/15073147.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有