笛卡尔树
因为上年 CSP-S 考了,但我并不会建树,于是今年初赛前来学学(虽然出的概率是微乎其微的了)
笛卡尔树满足两个条件:
-
- 它是一棵二叉搜索树
-
- 它是一个小根堆
若树上每个结点都有一个键值二元组 \((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\) 子树的大小)
对于转移,有两种形式:
-
- 全都是儿子的子树来填
-
- 儿子的子树填了一部分,当前点填了一部分
对于第一种,直接方案数相乘即可,典型的树形背包
对于第二种,我们枚举子树一共要放 \(j\) 个,当前点要放 \(k\) 个,那么就有转移:
我们知道,一个 \(n\times m\) 的矩阵要选 \(k\) 个数,一共有 \(C_n^k\times C_m^k\times k!\) 种,代表选出一些行、列并进行组合
而因为儿子已经选了一些数,因此能选的矩阵行列也要做出相应的修改