最值分治生成树
全文5368k。
额...只不过是因为刷题赛里出现了两道笛卡尔树,所以特意从新拿出来审视了一遍。
今天晚上要 Hello 2023,所以可能更没有时间补那道多项式了qwq。
至于线段树,那又只能明天学了/bai
笛卡尔树#
定义:满足堆性质的二叉搜索树,也就是常用的 Treap。
性质:中序遍历是原序列;父亲的权值比儿子小(以小根堆为例)
如果这是一个全序关系,那么这个笛卡尔树是唯一的。
建树:
笛卡尔树可以通过单调栈 构建。具体伪代码如下:
例 1 洛谷P5854【模板】笛卡尔树
https://www.luogu.com.cn/problem/P5854
给定一个 的排列 ,构建其笛卡尔树。
模板题。
随机笛卡尔树的树高是 的,其实是调和级数。
例 2 AGC028B Removing Blocks
https://www.luogu.com.cn/problem/AT_agc028_b
有 个数,每个数有一个全会 。进行 次操作,每次操作选择一个数删掉,代价是所有和其连通的没被删掉的数的权值和,求所有 种删数方法的代价和。
考虑对删除序列建小根堆笛卡尔树,那么每个点的贡献即为子树中 的和。转换为每个点贡献是 ,那么所求即为期望深度。根据前几天平衡树的那个证明,可以发现这个期望深度应该是 。。这样就可以 计算了。
例 3 RMQ Similar Sequence
Petrozavodsk Summer 2018. Day 4. Xi Lin Contest
给定序列 A,序列 B 的每个元素在 之内随机(实数),B 的价值是,当 B 和 A 的笛卡尔树同构时为元素和,否则是 。求 B 的价值的期望。定义值相同时排在前面的更大。
由于是在实数中随机,所以两个数相等的概率是 ,那么可以假设 B 是一个排列,一个排列与 A 的笛卡尔树同构,其实就是拓扑序相同,那么 B 的个数就可以算出了。即为 在 中随机一个数的期望是 ,所以 个数的和的期望就是 用这个值去乘上排列的个数即可得到答案。
code
有关深度的计数,以及一些和深度有关的结论。
例 4 CF1220F Gardener Alex
https://codeforces.com/problemset/problem/1220/F
给定长度为 的排列,可以将前 个元素移动到最后,所有可能的排列的小根笛卡尔树的最大深度的最小值。
考虑对于两个位置 ,什么时候 是 的祖先,也就是 的时候。那么这道题,我们就可以模拟移动的过程,每次找到第一个大于他的位置,然后前面的位置都可能被贡献到,用一个线段树来维护即可。code
例 5 USACO19DEC Tree Depth P
https://www.luogu.com.cn/problem/P5853
对每个数求出所有逆序对数是 的长度为 的排列的笛卡尔树上的深度和,深度定义为根到它的点数。
有一个算逆序对的方法,是按顺序从小到大加入,那么这样每次可以贡献的逆序对数刚好从 到 ,那么就相当于卷上一个 这样的 OGF。最后答案就是 。那么回到这道题,根据上一题的结论,考虑 两个点什么时候 是 的祖先,那么就是 是 这个区间中最小的数。
当 的时候,按照 的顺序填数,否则我们按照 的顺序填数,容易发现这样的效果和之前是一样的,唯一不同的是 这个位置的逆序对数是确定的,不能算进贡献。 时多贡献的逆序对数是 ,否则是 ,然后 这个 OGF 也不用贡献进答案。
那么就有了一个做法,枚举所有 ,用多项式除法(回退背包),把这一项的贡献消除,然后枚举所有 ,找到这一项 的贡献。
暴力实现多项式乘法+除法,总的复杂度是 。code
例 6 HDU6854 Kcats
前缀 的单调栈大小,即 号节点在全局的笛卡尔树上对应的位置的所有在左边的祖先个数,考虑dp,设 代表区间 的笛卡尔树的根的左边祖先有 个的方案数。
转移即枚举最小值的位置 ,然后从 转移。
复杂度 ,比较卡常,建议参考代码的卡常技巧。code
以 为根的笛卡尔树,代表一段区间,区间最小值是 上的值。区间 的最小值是 上的值。所以当遇到区间 rmq 作为要求/条件/所求的时候不妨想一想笛卡尔树。
例 7 Periodni
https://www.luogu.com.cn/problem/SP3734
给定一个网格图,第 高度为 。往网格里填 个数,同一列不能填两个数,同一行不能填两个数。如果中间有断开则不算同一行,问方案数。
要求即为对于同一行的数,放在高度 的位置,那么 。看到这个区间最小值想到小根堆笛卡尔树,建出笛卡尔树后就是一个树形背包问题,然后转换为在 的矩阵中选 个数的方案数,即为 。于是就可以直接dp了,复杂度 。
例 8 CF1580D Subsequence
将式子化以下,。
后面那个东西可以用笛卡尔树转换为 ,然后我们定义边权为 。
那么即可转换为选 个点使得其距离和最大,直接树形背包即可。
例 9 ZJOI2012 小蓝的好友
https://www.luogu.com.cn/problem/P2611
有一个 的图,图上有 个随机的点,询问有多少矩形包含至少一个点。。
转换为对不包含任意一个点的矩形计数,考虑枚举矩形的底,求出每一列距离这一行最近的点的高度,记为 ,然后转换为计数 。这个可以用笛卡尔树来维护,即维护 的和。还要可以单点修改,用 treap 维护,由于数据随机所以复杂度正确。
例 10 JOISC2020 星座 3
本题有一个很妙的贪心做法,但是和本文无关,所以就不再多做介绍。
两个星星是否可以组成一个星座,显然和他们之间的最高的小船有关,那看到这个自然想到笛卡尔树。考虑 dp,转换为求最大保留多少,如何消除后效性。容易发现最大值上方的部分只能保留一个,所以设 代表 子树内最大星星高度是 。暴力转移很显然,考虑如何优化。发现我们需要的时候区间加,对应位置合并求 ,以及单点修改,于是可以线段树合并维护,树上线段树合并时空复杂度均为 。
笛卡尔树本质是最值分治的结构
其实就是笛卡尔树的结构,找到最值,然后分成两边递归。
例 11 P4755 Beautiful Pair
https://www.luogu.com.cn/problem/P4755
有个数列 ,当一个数对 满足 和 的积不大于 ,这个数对是美丽的。请你求出美丽的数对的数量。
建出大根笛卡尔树,然后预处理出子树的区间,启发式分治,每次只遍历小的那一边,然后处理成区间询问。离线扫描线,然后离线扫描线即可。复杂度可以做到 。code
例 12 IOI2018 meetings 会议
设 代表区间 的答案。设 是 中最大的元素的位置。那么可以如此转移 。
考虑建出笛卡尔树,那么对于 的子树,可以来维护对于区间内的 dp 值。考虑维护 和 ,如果这些值被维护出来后直接枚举询问就好了。假设 的父亲是 ,不妨设 ,那么我们就是要维护 。
那么根据转移方程 ,考虑用线段树来优化。首先先给第一部分区间加。而这个 显然是单调的,后者是一条直线,找到交点之后就可以区间赋值了,注意线段树pushdown
的顺序,应该先赋值再加。对于右半边的部分直接继承就好啦。
其实也就是这个dp是一个分治信息,可以快速维护。最后的复杂度为 。
笛卡尔树合并
可以参考之前2022.12.30的闲话。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】