Loading

P1377 [TJOI2011] 树的序

题意

输入 \(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;
}
posted @ 2024-08-23 16:43  SunnyYuan  阅读(1)  评论(0编辑  收藏  举报