CSP2025 - 提高组生成树和笛卡尔树专题
P3639 [APIO2013] 道路费用
首先发现旧边和新边的限制我们非常不好处理,但是新边只有 \(20\) 条,所以最小生成树的形态变化应该不大。换句话说,有很多的旧边是一直在最小生成树上的。考虑优先找出这些边。具体而言,我们把所有的新边全部加入图中,然后跑 Kruskal。这一遍找出的旧边就是永远位于最小生成树上的边。
把这些旧边的连通块缩成一个点。经过这一步就只剩下 \(k+1\) 个点了,数据范围显著缩小。
现在剩下的旧边数量虽然规模还是 \(O(m)\) 的,但因为只剩下 \(k+1\) 个点,所以很多边都是无用的,我们只需保留边权最小的 \(k\) 条旧边。
做完了这些工作,我们就可以 \(2^{20}\) 枚举最小生成树中有哪些新边了。至于新边的边权怎么确定,我们考虑到:刚才处理出的 \(k\) 条不一定在最小生成树中的旧边,每一条实际上都提供了一条限制。对于一条不一定在最小生成树中的旧边 \((u,v,w)\),实际上限制了树上 \(u\) 到 \(v\) 的路径的边权最大值不能超过 \(w\)。而边权最大值这个东西可以用 LCA 处理,因为只有 \(k+1\) 个点,所以暴跳父亲就可以处理。
最终对于在最小生成树中的新边计算贡献即可。
P8626 [蓝桥杯 2015 省 A] 灾后重建
\(50000\) 的数据范围,\(5~\rm s\) 的时间限制,非常根号分治。
题目中又一次出现了边权最大值这个东西,根据经验直接在最小生成树上处理。所以这题的第一步就是 Kruskal,第二步就是倍增处理 LCA 和边权最大值。接下来考虑怎么快速处理询问。
然后就是本题的精粹了:
- 当 \(K_i>\sqrt N\),说明参与询问的点只有 \(\sqrt N\) 个。此时我们直接建立虚树,对于虚树上的每一条边找出这条边连接的两点在原树上的边权最大值即可。
- 当 \(K_i\le\sqrt N\),此时的 \(K\) 的种类数就被我们过滤成了 \(\sqrt N\) 个,把它们离线下来按照 \(K\) 排序,对于每一个 \(K\) 的所有余数都计算出两两之间的边权最大值,放入线段树中。查询的时候在线段树中查询区间最大值即可。注意为了保证余数相等的数在线段树中连续,需要重新给定编号,这一步的细节特别需要注意。
最后的复杂度就是 \(O(N\sqrt N\log N)\)。
CF1580B Mathematics Curriculum
把 “包含 \(x\) 的子串最大值个数为 \(m\)” 这个条件转化为 \([1,x)\) 中的前缀最大值加上 \((x,n]\) 中的后缀最大值数量为 \(m\),发现这个东西就是笛卡尔树上 \(\boldsymbol x\) 的层数。于是问题转化为,有多少形态不同的笛卡尔树满足层数为 \(m\) 的节点数等于 \(k\)。
然后就可以 DP 了。设 \(f_{n,m,k}\) 表示笛卡尔树大小为 \(n\)、层数为 \(m\) 的点有 \(k\) 个的方案数。转移的时候枚举笛卡尔树一个儿子的大小和里面深度为 \(m\) 的个数,有:
但这样是过不去的,\(100\) 想要过 \(O(n^5)\) 哪有那么容易。重点优化转移边界,发现 \(j\) 这个东西不仅有上界还有下界,下界就是 \(i+k+1-n\)。然后记搜就把这题草过去了。
P10173 「OICon-02」maxiMINImax
和笛卡尔树没有什么关系。看到三个区间应该想到枚举中间那个,看到统计子串个数应该想到对每个点单独计算贡献。然后就可以单调栈求出每个点向左/右最远到哪能使其成为区间最大/最小值,然后就可以计算出 \(c_i,d_i\) 分别代表第 \(i\) 个点作为区间最小/最大值时的方案数。
所以此时我们从小到大地枚举每一个数作为中间区间的最小值,记为 \(\min_2\),这个数所带来的贡献就是
把式子拆开,发现只需用树状数组维护 \(\sum d_{\max_1}\)、\(\sum d_{\max_3}\)、\(\sum d_{\max_1}\max_1\)、\(\sum d_{\max_3}\max_3\) 即可计算。