笛卡尔树

因为上年 CSP-S 考了,但我并不会建树,于是今年初赛前来学学(虽然出的概率是微乎其微的了)


笛卡尔树满足两个条件:

    1. 它是一棵二叉搜索树
    1. 它是一个小根堆

若树上每个结点都有一个键值二元组 \((k,w)\),那么关于 \(k\) 满足二叉搜索树的性质;关于 \(w\) 满足小根堆的性质

现在考虑建树过程:

我们将元素按照 \(k\) 从小到大排序

维护笛卡尔树的右链(就是从根一直向右儿子走,直到没有右儿子)

当加入一个元素 \(a\) 时,我们从右链底部向上依次比较,对于出现的第一个满足 \(w_x<w_a\) 的元素 \(x\),我们将 \(a\) 的左儿子设为 \(x\) 原本的右儿子,将 \(x\) 的右儿子设为 \(a\)

然后更新右链,可以用栈来维护

(from OI-wiki)


代码

(虽然是模板题,但需要细节卡常)


P1377 [TJOI2011] 树的序

我们观察原树发现,对于下标,它满足小根堆的性质;对于权值,它满足二叉搜索树的性质

因此我们可以将原本的权值当作下标,原本的下标看作权值,建立一棵笛卡尔树

最后按照先序遍历输出笛卡尔树上的下标即可

代码


P6453 [COCI2008-2009#4] PERIODNI

一道笛卡尔树优化 DP 的好题

我们考虑用高度为权值建出一棵笛卡尔树,跑树形 DP

我们设 \(f[i][j]\) 表示 \(i\) 子树内放了 \(j\) 个数的方案数

\(i\) 个结点能放的高度应该是 \(h_i-h_{fa[i]}\),个数则是 \(sz[i]\)\(i\) 子树的大小)

对于转移,有两种形式:

    1. 全都是儿子的子树来填
    1. 儿子的子树填了一部分,当前点填了一部分

对于第一种,直接方案数相乘即可,典型的树形背包

对于第二种,我们枚举子树一共要放 \(j\) 个,当前点要放 \(k\) 个,那么就有转移:

\[f[i][j]=\sum_{k = 1}f[i][j - k]\times C_{h_i-h_{fa[i]}}^j \times C_{sz[i]-(j-k)}^j\times j! \]

我们知道,一个 \(n\times m\) 的矩阵要选 \(k\) 个数,一共有 \(C_n^k\times C_m^k\times k!\) 种,代表选出一些行、列并进行组合

而因为儿子已经选了一些数,因此能选的矩阵行列也要做出相应的修改

代码

posted @ 2022-09-16 10:10  zuytong  阅读(27)  评论(0编辑  收藏  举报