笛卡尔树知识点+思路

笛卡尔树性质:

每个结点存储 (k,w) ,即一个序偶

  • 对于k而言,是一个二叉搜索树(满足条件:根节点大于左节点,小于右节点)

  • 对于w而言,是一个小根堆/大根堆(满足条件:根节点值小于/大于左,右节点值)

笛卡尔树不是平衡的

笛卡尔树的构建:

如何使一个数组->笛卡尔树?

单调栈O(n),处理出每一个结点的左儿子,右儿子,权值w

QQ_1755002624319

举例:对于上图的数组 a=[9, 3, 7, 1, 8, 12, 10, 20, 15, 18, 5],构建一颗小根堆笛卡尔树

显然序偶 (k,w) = (元素下标,元素大小)

我们使单调栈元素是单调递增

从左至右:显然元素下标是单调增的,所以为了满足二叉搜索树的条件,我们首先会把这个结点视为右结点(因为前面元素下标都比该结点小)

然后通过 维护的单调栈 判断这个结点是哪一个结点的右结点

  1. 如果单调栈为空,那么该结点是初始结点,不用判断左右结点情况

  2. 如果单调栈非空:

若栈顶元素大小大于该元素大小,由于我们需要维护小根堆,显然当前结点不能是栈顶结点的儿子。直接出栈

若栈顶元素大小小于该元素大小,那么我们直接把当前结点看作栈顶结点的右结点

同时,我们需要维护出栈的最后一个元素结点,我们将该元素结点看作当前结点的左结点(元素大小既大于当前结点,元素下标又小于当前结点)

特别的,如果不断出栈,最后栈为空,说明当前结点看作根结点

最后将当前结点入栈

参考代码

struct node{
    int l=0,r=0,fa=0;
    int val;
};

int n;cin>>n;
    vector<int>a(n+1);rep(i,1,n)cin>>a[i];
    vector<node>tr(n+1);
    stack<int>stk;
    rep(i,1,n){
        int L=0,R=0;
        while(stk.size()&&a[stk.top()]>a[i]){
            L=stk.top();
            stk.pop();
        }

        if(L!=0){
            tr[L].fa=i;
            if(stk.size())tr[stk.top()].r=i;
        }
        else if(stk.size()){
            tr[stk.top()].r=i;
        }
        stk.push(i);

        tr[i].val=a[i];
        tr[i].l=L;
        tr[i].r=R;
    }
posted @ 2025-08-12 21:06  Marinaco  阅读(21)  评论(0)    收藏  举报
//雪花飘落效果