我们考虑将元素按照键值 k 排序。然后一个一个插入到当前的笛卡尔树中。那么每次我们插入的元素必然在这个树的右链(右链:即从根结点一直往右子树走,经过的结点形成的链)的末端。于是我们执行这样一个过程,从下往上比较右链结点与当前结点 u 的 w,如果找到了一个右链上的结点 x 满足 x_w<u_w,就把 u 接到 x 的右儿子上,而 x 原本的右子树就变成 u 的左子树。
新建一个大小为 n 的空栈。用 top 来标操作前的栈顶,k 来标记当前栈顶。
For i := 1 to n
k := top
While 栈非空 且 栈顶元素 > 当前元素
k--
if 栈非空
栈顶元素.右儿子 := 当前元素
if k < top
当前元素.左儿子 := 栈顶元素
当前元素入栈
top := k
这道题你可 DP,可单调栈,但你万万没想到的是它也可以笛卡尔树!具体地,我们把下标作为键值 k,h_i 作为键值 w 满足小根堆性质,构建一棵 (i,h_i) 的笛卡尔树。
这样我们枚举每个结点 u,把 u_w(即结点 u 的高度键值 h)作为最大子矩阵的高度。由于我们建立的笛卡尔树满足小根堆性质,因此 u 的子树内的结点的高度都大于等于 u。而我们又知道 u 子树内的下标是一段连续的区间。于是我们只需要知道子树的大小,然后就可以算这个区间的最大子矩阵的面积了。用每一个点计算出来的值更新答案即可。显然这个可以一次 DFS 完成,因此复杂度仍是 O(n) 的。