P1377 [TJOI2011] 樹的序 (笛卡爾樹)

pipipipipi43發表於2024-03-18

笛卡爾樹模板題

題目給出一個生成序列 要我們構造一個 二叉搜尋樹。
所以值要滿足二叉搜尋樹的性質。
因為給出的是生成序列,所以序列的下標是滿足 最小堆的性質。
那麼可以按照滿足二叉搜尋樹的那一維度進行排序也就是值進行排序。
然後進行構建即可。
最後進行先序遍歷即可獲得答案。

大致的構建方式:
1.先按照值從小到大排序。
2.按照排序順序一一處理元素。
3.用一個棧來維護笛卡爾樹 最右端的一條鏈
4.每個元素進來後,因為要滿足二叉搜尋樹的性質,所以一定是在這條鏈上的
5.那麼現在就是要確定具體在 最右端的鏈上的哪個位置進行插入
6.因為此時下標又滿足最小堆的性質,所以 棧上維護的鏈從棧底到棧頂是遞增的
7.那麼就可以在從棧頂的元素開始找第一個滿足小於 當前 元素下標的。
8.找到之後 當前元素就變成 此時棧頂元素的右兒子,原來棧頂的右兒子變成當前元素的左兒子
9.重複 5~8的過程就能完成實現。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>pir;
const int N = 1e5 + 5;
int ls[N], rs[N], n, stk[N];
pir a[N];
void dfs(int u)
{
    cout << a[u].first << " ";
    if(ls[u])dfs(ls[u]);
    if(rs[u])dfs(rs[u]);
}
void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i].first;
        a[i].second = i;
    }
    sort(a + 1, a + n + 1);
    int top = 0;
    for(int i = 1; i <= n; i++)
    {
        int k = top;
        while(k > 0 && a[stk[k]].second > a[i].second)k--;
        if(k)rs[stk[k]] = i;
        if(k < top)ls[i] = stk[k + 1];
        stk[++k] = i;
        top = k;
    }
    dfs(stk[1]);
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    solve();
}

相關文章