笛卡尔树

oi wiki 上的图很形象啊,我 he 了不少。

引入

image

所以 treap 也是一种笛卡尔树。

一般来说,\(k\) 是下标,\(w\) 是权值,这样会有一些好的性质,子树是连续区间,且整棵树满足小根堆。在处理一些区间最值划分之类的问题比较强大。

比如,因为其权值满足堆,子树是连续区间,所以笛卡尔树中两个节点的 LCA 即为区间最值,配合 \(O(n)\) LCA 算法可以做到线性复杂度处理区间最值问题。

构建

以小根堆为例。

\(k\) 为下标,\(w\) 为权值,因为二元组中的一维 \(k\) 是单调插入的,所以最后一个节点必然是整个二叉树中最右边的一棵树,只能是根或者右儿子,所以整个插入过程只在一条右链上进行,考虑用栈维护这个右链。

令当前插入需要被插入的节点为 \(p\),目前要插入 \(i\) 节点。如果 \(w_i>w_p\),直接成为其右儿子,否则向上跳右链,直到满足或者右链为空,插入后再更新 \(i\) 的儿子为上一个退出的节点即可。

每个节点最多进出栈各一次,复杂度 \(O(n)\)

image

例题

P1377 [TJOI2011] 树的序

image

直接根据题目要求暴力插入的平均时间复杂度为 \(O(n\log n)\),单调序列可以卡为 \(O(n^2)\)

简单分析题目,其实就是构建一颗平衡树,因为后插入的节点一定是之前节点的儿子,对应下标满足小根堆,权值满足二叉搜索树。满足笛卡尔树 \((k,w)\) 的要求,直接构建即可。

构建完成之后就是一个中序遍历,保证字典序最小即可。时间复杂度 \(O(n)\)

hdu6305 rmq similar sequence

image

两个序列相似当且仅当每个节点作为最值控制的区间是一样的,相当于笛卡尔树相同。

由于 \(B\) 是实数序列,存在相同元素的概率为 \(0\),所以 \(B\) 序列可视为一个 \(n\) 的排列。

任意一个排列的笛卡尔树与 \(A\) 的笛卡尔树相同的概率为 \(p\),那么 \(ans=\frac{1}{2}\times n\times p\)

如果要求笛卡尔树相同,就要求每个区间的最值位置相同(就是题目原意),对应的在一个大小为 \(size_p\) 的子树中,要求 \(p\) 为根节点即可,概率为 \(\frac{1}{size_p}\)。所以对应的 \(p=\prod_{1}^{n}\frac{1}{size_i}\)

[ARC189D] Takahashi is Slime

image

暴力 \(O(n^2)\),实际上这还是区间最值划分之类的问题,建出笛卡尔树,每一个节点都可以吃他的子树,然后统计子树权值和与父亲比较,如果大于,就以此类推,一路往上吃吃吃,当不能吃的时候就得到了答案。建出树后 dfs 一遍即可。

P6453 [COCI 2008/2009 #4] PERIODNI

image

数据范围 \(500\),也许是一个二维或者三维的 DP,暴力想到 \(f_{l,r,k}\) 表示在 \([l,r]\) 中填了 \(k\) 个的方案数。但这样根本无法合并。

我们发现隔断这个机制很重要,也许换一种角度,从上到下转移会比较好,首先在最上面全部隔断,依次往下推,隔断重新连接时合并两个区间,由于存在隔断,所以隔断以上方案数直接相乘即可,考虑新连接的一行,讨论新的一行中填在哪一列进行转移,这个转移的顺序刚好是笛卡尔树的顺序,转移对应子树的合并。

详细过程参考题解吧,提供思路。

[HDU-6854] Kcats

先考虑没有 -1 怎么做,发现区间最小值可以将区间划分为两个毫不相干的部分,而最小值对应位置就是最右边的 1 的位置,利用这一性质,每次找到最小值的位置分治即可,相当于设 \(f_{l,r}\) 表示 \([l,r]\) 对应区间的方案数即可,根据最小值位置 \(p\) 做转移,有转移 \(f_{l,r}=f_{l,p-1}\times f_{p+1,r}\times {r-l\choose p-l}\)

如果加上 -1 的话就说明最小值的位置不再确定,直接枚举该位置对应的单调栈大小,类比发现填到第 \(i\) 个位置时单调栈的大小就是笛卡尔树上 \(i\) 节点的左父亲个数加一。

\(dp_{i,j,d}\) 表示 \([i,j]\) 区间的根节点对应的单调栈大小为 \(d\),先给出转移 \(dp_{i,j,d}=\sum_{k=i}^j dp_{i,k-1,d}\times dp_{k+1,j,d+1}\times C^{k-i}_{j-i}\)

左边的 \(d\) 对应左子树,这时将 \(k\) 加入,左子树会全部删除,而需要保留 \(d\) 的深度,所以是 \(d\)
右边的 \(d+1\) 对应右子树,右子树会直接加到 \(k\) 上,所以他的根节点深度是 \(d+1\)
转移中的 \(k\) 是枚举最小值(树根)位置,这个 \(d\) 就相当于枚举不存在的 \(a_k\),如果 \(a_k\) 存在那么 \(d\) 确定,不可再枚举。

总结

笛卡尔树一般不会裸考,重要的是运用其处理区间最值思想,笛卡尔树上 DP 是一个很好的 trick,大家可以多练几道。

posted @ 2026-07-16 09:11  Ishar-zdl  阅读(43)  评论(0)    收藏  举报