定义
笛卡尔树是一种二叉树,每一个结点由一个键值二元组 构成。
性质
- 满足 BST 的性质
- 满足 min-heap 的性质。
- 如果笛卡尔树的 值确定,且 互不相同, 互不相同,那么这个笛卡尔树的结构是唯一的。

给定一个数组,可以建出对应的笛卡尔树,将数组的值作为 ,数组的index作为 ,建树的思想是:
每次取当前数组中最小的那个元素,将它左边作为左子树,右边作为右子树,然后递归建树。
通过单调栈维护从根出发的向右的链(递增栈),在加入一个新元素 前(弹出过程已经完成):
- 如果之前有弹出元素,那么最后一个弹出的元素作为 的左child。
- 如果此时栈上有元素,那么栈顶的元素的右 是 。
应用
笛卡尔树可以用于 或者 建BST,见 例2
题意
给定一个 到 的permutation,构建出笛卡尔树。
代码
copy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <bits/stdc++.h> using namespace std; const int maxn = 1e7+5; struct Node { int lc, rc, p, idx; } a[maxn]; int n; int main() { fastio; cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i].p; a[i].idx = i; } stack<pii> st; for (int i = 1; i <= n; i++) { int last = 0; while (st.size() && st.top().first > a[i].p) last = st.top().second, st.pop(); if (last) a[i].lc = last; if (st.size()) a[st.top().second].rc = a[i].idx; st.push({a[i].p, i}); } ll ans1 = 0, ans2 = 0; for (int i = 1; i <= n; i++) { ans1 ^= ((ll)i * (a[i].lc + 1)); ans2 ^= ((ll)i * (a[i].rc + 1)); } cout << ans1 << " " << ans2 << "\n"; }
|
题意
给定一个 到 的permutation,代表按照这个顺序将这些元素插入到一个 BST 中。
求所有能够生成同样BST的所有permutation中,字典序最小的一个。
其中,。
题解
很容易可以想到一个思路:按照给定的序列,把BST建出来,然后求这个BST的pre-order就是字典序最小的了(因为先访问左边,再访问右边,并且pre-order保证了结构一致,所以pre-order即是所求)。
现在问题来了:根据这个序列建BST,最坏情况下是 的,怎么加速?
注意到,根据一个序列建BST,得到的BST满足两个性质:
- 每个节点的 index 满足小根堆的性质:因为在BST中,一个 的index一定比它的 parent 的index更加靠后。
- 每个节点的值 (value) 满足BST的性质:因为这就是一个BST。
回忆笛卡尔树的性质:
- 每个节点的 index 满足BST性质。
- 每个节点的 value 满足小根堆性质。
恰好是反过来的!
于是我们将原序列的 index 与 value 反过来,然后建立笛卡尔树,建好以后再反一次,就得到了想要的BST了。
• 由于这个题给定的 value 是 到 的排序,所以可以直接 反过来,否则需要 。
• BST的根就是栈最底下的那个节点(因为我们维护的是一个从根开始向右的链)。
代码
copy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <bits/stdc++.h> using namespace std; const int maxn = 1e5+5; struct Node { int lc, rc, p, idx; } a[maxn]; int idx_to_val[maxn], val_to_idx[maxn]; int n; void dfs(int u) { cout << idx_to_val[a[u].p] << " "; if (a[u].lc) dfs(a[u].lc); if (a[u].rc) dfs(a[u].rc); } int main() { fastio; cin >> n; for (int i = 1; i <= n; i++) { int val; cin >> val; idx_to_val[i] = val; val_to_idx[val] = i; a[i].idx = i; a[val].p = i; } stack<pii> st; for (int i = 1; i <= n; i++) { int last = 0; while (st.size() && st.top().first > a[i].p) last = st.top().second, st.pop(); if (last) a[i].lc = last; if (st.size()) a[st.top().second].rc = a[i].idx; st.push({a[i].p, i}); } int rt = -1; while (st.size()) rt = st.top().second, st.pop(); dfs(rt); cout << "\n"; }
|
Author
tom0727
LastMod
2025-05-01
(d141563)
,更新历史
License
CC BY-SA 4.0