题意
输入 \(n\) 个数字,按照顺序将这 \(n\) 个数字插入 BST,在保证 BST 的结构不变的情况下,重排插入顺序,使得其字典序最小。
思路
这个题目很好地利用了笛卡尔树的性质。
我们考虑最后建出来的 BST 的中序遍历一定是 \(1, 2, 3, \cdots , n - 1, n\),不难想到,BST 的一个子树的根节点一定是最先添加的,否则这个位置就不是它的了。
所以我们考虑建笛卡尔树,设 \(a_i\) 表示数字 \(i\) 在原插入顺序的第 \(a_i\) 位,我们将 \(a\) 数组从前往后插入笛卡尔树,这保证了其中序遍历为 \(1, 2, 3, \cdots , n - 1, n\),保证其是一个合法的 BST,并且每个数字代表的下标满足堆的性质,所以下标靠前的一定在笛卡尔树的浅层。
最后前序遍历一边即可,理由同“BST 的一个子树的根节点一定是最先添加的,否则这个位置就不是它的了”。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, a[N];
int lc[N], rc[N];
int stk[N], top;
void dfs(int u) {
cout << u << ' ';
if (lc[u]) dfs(lc[u]);
if (rc[u]) dfs(rc[u]);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
a[x] = i;
}
for (int i = 1; i <= n; i++) {
int k = top;
while (k && a[stk[k]] > a[i]) k--;
if (k) rc[stk[k]] = i;
if (k < top) lc[i] = stk[k + 1];
stk[++k] = i;
top = k;
}
dfs(stk[1]);
return 0;
}
标签:插入,笛卡尔,int,top,P1377,stk,BST,TJOI2011
From: https://www.cnblogs.com/Yuan-Jiawei/p/18376388