笛卡尔树
创建时间:2025-12-30
笛卡尔树的定义
笛卡尔树是一种特殊的二叉树,它同时具备二叉搜索树和二叉堆的性质。
具体的,笛卡尔树的每个节点都有一个键值 \(key\) 和权值 \(val\),而一个节点 \(u\) 的左子树中所有节点的 \(key\) 都小于等于 \(key_u\),右子树中所有结点的 \(key\) 都大于等于 \(key_u\),且 \(u\) 一定是 \(u\) 的子树中 \(val\) 最大的节点
之一。
在实际问题中,键值通常等于序列的索引,当然也有题目中不等于。
构造笛卡尔树
以 P5854 【模板】笛卡尔树 为例:给定序列 \(a_1, a_2, a_3, \cdots, a_n\),以 \(i\) 为键值,\(a_i\) 为权值建笛卡尔树。设 \(i\) 的左儿子、右儿子分别为 \(l_i, r_i\),输出 \(\operatorname{xor}_{i=1} l_i\) 和 \(\operatorname{xor}_{i=1}^n r_i\)。
为方便插入节点,我们称在一棵笛卡尔树上从根开始一直向右子树走直到右子树为空,得到的链为该笛卡尔树的右链。
例如下图中笛卡尔树的右链为红色部分(节点编号为其键值):

现在考虑在右链末端插入一个键值为 \(10\) 的节点 \(x\),显然该操作不影响笛卡尔树的二叉搜索树性质。但这么做可能破坏笛卡尔树的二叉堆性质,故应该在 \(x\) 的权值比 \(x\) 父节点的更优时将 \(x\) 上浮,直到 \(x\) 成为根节点或 \(x\) 的权值比 \(x\) 的父节点劣。像这样:

直接上浮保证了笛卡尔树的二叉堆性质。然而,这可能又破坏了笛卡尔树的二叉搜索树性质,这时只需要把节点 \(7\) 挂在 \(x\) 的左子树上就行了,即让 \(7\) 作为 \(x\) 的左儿子。

这样就成功将 \(x\) 插入笛卡尔树了。不难发现,这既没有破坏二叉搜索性质,有没有破坏二叉堆性质。
那么怎么实现这一过程呢?
根据笛卡尔树的定义知右链是一条键值单调,权值也单调的链,所以想到用单调栈维护笛卡尔树的右链。因为新节点 \(x\) 上浮过程中被顶替的所有祖先节点在 \(x\) 插入完成后都在 \(x\) 的左子树中,所以它们都不再是右链的一部分。即每个节点只会进栈一次,最多出栈一次,总建树时间复杂度为 \(O(n)\)。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7 + 50;
int n, p[N], top, stk[N];
struct Node {
int lc, rc, val;
} tr[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> p[i];
for (int i = 1; i <= n; i++) {
tr[i].val = p[i];
int k = top;
while (k && p[i] < p[stk[k]])
k--;
if (k)
tr[stk[k]].rc = i;
if (k < top)
tr[i].lc = stk[k + 1];
stk[top = ++k] = i;
}
long long ans1 = 0, ans2 = 0;
for (int i = 1; i <= n; i++) {
ans1 ^= 1ll * i * (tr[i].lc + 1);
ans2 ^= 1ll * i * (tr[i].rc + 1);
}
cout << ans1 << ' ' << ans2 << '\n';
return 0;
}
笛卡尔树的应用
笛卡尔树的重要性质:
- 笛卡尔树建树的时间复杂度为 \(O(n)\),空间复杂度也为 \(O(n)\),在卡空间或者查询不是特别多的情况下可以代替 ST 表
- 笛卡尔树的每个节点的管辖范围是该节点作为区间最大/小值的最大区间
- 区间 \([l,r]\) 的最值为从下往上第一个管辖范围包含 \([l,r]\) 的节点的权值,且这个节点是 \(\operatorname{LCA}(l,r)\)
其中第 2 条很容易和 DP 一起考,通过笛卡尔树上 DP 优化和区间最值有关的状态转移。
运用笛卡尔树本身的定义以及这些性质,可以解决很多题目,例:
P1377 [TJOI2011] 树的序(笛卡尔树的建树);
P4147 玉蟾宫(笛卡尔树的建树及基础性质);
P3793 由乃救爷爷(笛卡尔树维护静态区间最大值);
CF1580D Subsequence(笛卡尔树上DP);
P5044 [IOI 2018] meetings 会议(笛卡尔树上分治+线段树优化DP)。

浙公网安备 33010602011771号