结合二叉搜索树与堆的双重性质,利用单调栈实现 $O(N)$ 极速建树
笛卡尔树(Cartesian Tree)是一种二叉树,由一个唯一的数值序列构建而成,它同时具有以下性质(以小根堆为例):
我们使用一个单调递增栈来存储当前树中从根节点一直往右伸展的右斜链节点(索引与数值均单调递增):
struct CSNode {
int val, id;
int left, right; // 左右孩子索引
} tree[MAXN];
void buildCartesianTree(int n, const vector<int>& a) {
stack<int> stk; // 存储数组索引的单调递增栈
for (int i = 0; i < n; i++) {
tree[i].val = a[i];
tree[i].id = i;
tree[i].left = tree[i].right = -1; // 初始无孩子
int lastPopped = -1;
// 从栈中弹出所有大于当前值的元素
while (!stk.empty() && tree[stk.top()].val > a[i]) {
lastPopped = stk.top();
stk.pop();
}
// 1. 最后一个弹出的节点成为当前节点的左孩子
if (lastPopped != -1) {
tree[i].left = lastPopped;
}
// 2. 当前节点成为此时栈顶的右孩子
if (!stk.empty()) {
tree[stk.top()].right = i;
}
stk.push(i); // 当前节点入栈
}
}