笛卡尔树的妙用

前言笛卡尔树,与Treap类似,每个节点拥有两个值,key值和val值。key值是这个节点本身的大小值,在一颗treap中满足二叉查找树的性质,而val值则是一个随机值,学过treap的同学都知道,这个val值是拿来使得树的层高是期望log的,val值满足堆的性质,这里以小根堆为例讲解(当然大根堆不会有任何问题)。应用一般笛卡尔树都被用来建一颗treap,复杂度为O(n)的,n表示插入...
摘要由CSDN通过智能技术生成

前言

笛卡尔树,与Treap类似,每个节点拥有两个值,key值和val值。key值是这个节点本身的大小值,在一颗treap中满足二叉查找树的性质,而val值则是一个随机值,学过treap的同学都知道,这个val值是拿来使得树的层高是期望log的,val值满足堆的性质,这里以小根堆为例讲解(当然大根堆不会有任何问题)。

应用

一般笛卡尔树都被用来建一颗treap,复杂度为O(n)的,n表示插入的元素个数。
而暴力插入的话是O(n log n)的。
这里需要讲清楚的是,笛卡尔树建树,插入的元素必须保证key值递增,而val值是可以乱的,许多博客里没有讲,这里必须要强调一下。

实现

我们维护笛卡尔树的极右链,就是根,根的右儿子,根的右儿子的右儿子…….
放在一个栈里,栈底是根,这样很显然从栈顶到栈底,val值是不断变小的。
每当我们进入一个新的节点,我们从栈顶开始找,当找到第一个节点的val值比我小,那么我必须得是它的儿子,而我的key值又比他大,所以我作为它的右儿子,而原先它的右儿子key值比我小,所以作为我的左儿子,这样就维护了一个treap的性质,然后原来那个店变为了我的左儿子,所以就要从极右链中删掉,我加入到极右链中,这样每个点进栈一次,出栈一次,复杂度就是O(n)的,下面贴出具体的代码。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,关于用 C 语言建立笛卡尔树求解区间最值问题,我可以给你一些基本的思路和代码实现。 首先,笛卡尔树是带权值的树,其性质由下面的定理给出: 定理1:一个序列可以对应唯一的一棵笛卡尔树。 定理2:设在笛卡尔树上节点 u 和 v 的先后顺序为“按下标增大的顺序,在这个前提下按权值减小的顺序”,则 u 到 v(包括 u 和 v)路径上的点在原序列中构成了一个区间。 基于这两个定理,我们就可以使用笛卡尔树来解决区间最值问题,其基本思路如下: 1. 输入一个序列 a[N],构建对应的笛卡尔树。 2. 对于每个节点 u,记录其子树中最小值或最大值(根据具体问题而定)。 3. 对于每个询问,找到笛卡尔树上 u 和 v 两个节点,使得它们对应的区间包含询问区间 [L,R],那么 [L,R] 中的最值就是从 u 到 v 路径上的最小值或最大值(可以使用 st 表等数据结构进行维护)。 下面是用 C 语言实现笛卡尔树的基本代码,可以参考一下: struct Node { int val, idx; int fa, ch[2]; } tree[N]; int root, idx; int build(int l, int r) { // 构建笛卡尔树并返回根节点编号 if (l > r) return -1; int x = l; for (int i = l + 1; i <= r; i++) if (tree[i].val < tree[x].val) x = i; tree[x].ch[0] = build(l, x - 1); tree[x].ch[1] = build(x + 1, r); if (tree[x].ch[0] != -1) tree[tree[x].ch[0]].fa = x; if (tree[x].ch[1] != -1) tree[tree[x].ch[1]].fa = x; return x; } 现在我回答了你的问题,如果您有任何其他问题,可以随时问我。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值