笛卡尔树构建

//
//  main.cpp
//  数列构建笛卡尔树
//

#include <iostream>
using namespace std;

/*
                  35
                 /  \
               16    27
              / \   /  \
            12  15 19  18
 
         12 16 15 35 19 27 18
 
 */

/*
栈中的情况变化  是下标在栈中,用值表示易理解
 
 |   |     |   |     |   |     |   |     |   |     |   |     |   |
 |   |     |   |     |   |     |   |     |   |     |   |     |   |
 |   |     |   |     |   |     |   |     |   |     |   |     |   |
 |   |     |   |     |   |     |   |     |   |     |   |     |18 |<-top
 |   |     |   |     |15 |<-top|15 |     |19 |<-top|27 |<-top|27 |
 |12 |<-top|16 |<-top|16 |     |35 |<-top|35 |     |35 |     |35 |
 |___|     |___|     |___|     |___|     |___|     |___|     |___|
 */

//代码摘自笛卡尔树百度百科,
const int MAXN=100;

void computeTree(int A[MAXN], int N, int T[MAXN])
//T[i]储存每个结点的父结点(左右子树是无所谓的)
{
    int st[MAXN], i, k, top = -1;
    //从空栈开始
    //第i步,我们将A[i]插入栈中
    for (i = 0; i < N; i++)
    {
        //找到第一个大于等于A[i]的元素
        k = top;
        while (k >= 0 && A[st[k]] < A[i]) k--; //最大堆 如果是最小堆应该是 >
        //如上述,更改树的结构
        if (k != -1) T[i] = st[k];
        if (k < top) T[st[k + 1]] = i;
        //将A[i]插入栈中,并移除所有更大的元素
        st[++k] = i;
        top = k;//这里是令k为top,其实35上面还有数字15,只是top是35而已,下一回15就会被19覆盖了
    }
    //栈中的第一个元素就是树根,没有父节点
    T[st[0]] = -1;
}

int main()
{
    int A[MAXN]={12,16,15,35,19,27,18};
    int T[MAXN];
    computeTree(A, 7, T);
    for(int i=0; i<7; ++i)
        cout<<T[i]<<" ";
    return 0;
}

//1 3 1 -1 5 3 5 Program ended with exit code: 0

### 关于洛谷5854笛卡尔的解题思路 对于洛谷平台上的题目5854,涉及到构建笛卡尔来解决问题。笛卡尔是一种特殊的二叉结构,在此问题中用于处理特定的数据序列。 #### 构建笛卡尔的关键点在于: - **定义**:笛卡尔是一棵满足堆性质的二叉搜索。具体来说就是对于任意节点V,其左子中的所有键值均小于它自己的键值;右子中的所有键值大于等于它的键值,并且整个按照给定数组元素顺序形成前序遍历的结果[^1]。 - **特性应用**:利用这些特点可以在O(n)时间内完成构造操作,这对于优化算法效率至关重要。当面对需要频繁查询最值或者范围内的极值等问题时尤为有用[^2]。 针对本题目的实现方式如下所示: ```cpp #include <bits/stdc++.h> using namespace std; struct Node { int val, id; } nodes[100005]; bool cmp(Node a, Node b) {return a.val != b.val ? a.val < b.val : a.id > b.id;} int n, root = 0, fa[100005], chl[100005], chr[100005]; stack<int> s; void build() { memset(fa, -1, sizeof(fa)); for (int i = 1; i <= n; ++i) { nodes[i].id = i; scanf("%d", &nodes[i].val); } sort(nodes + 1, nodes + 1 + n, cmp); for(int i=1;i<=n;++i){ while(!s.empty() && nodes[s.top()].val<nodes[i].val){ if(chl[s.top()]!=-1&&chr[chl[s.top()]]=-1) chr[chl[s.top()]]=i; else{ chl[i]=chl[s.top()]; break; } s.pop(); } if (!s.empty()) { if(chr[s.top()]==-1||nodes[chr[s.top()]].val>=nodes[i].val) chr[s.top()]=i; else{ chl[i]=chr[s.top()]; chr[s.top()]=i; } } s.push(i); } } // 打印结果函数省略... ``` 上述代码实现了基于单调栈的方法快速建立笛卡尔的过程。通过比较当前节点与栈顶元素之间的关系决定父子连接方向,从而保证最终形成的既符合二叉搜索又具备最小/大堆的特点[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值