模拟赛
这里的题解在出题人的基础上进行补充。
T1
首先忽略所有全开的子树(在这样的子树内我们不应该选择任何路径),选一个关的点作为根
设 $f_{u,0/1,0/1/2}$ 表示满足条件
- $u$ 最后是关/开的,子树内其它点最后都是开的
- 子树内有 0/1/2 个路径端点,其它端点为 $u$
的最小路径长度
设加入 $u$ 的前若干个儿子后的结果为 $tmp_{0/1,0/1/2}$,需要加入儿子 $v$,转移的规则为:
- 关于端点个数这一维是个背包
- 路径拼接时,可能会多走一次某个点。具体地,当 $v$ 子树内的端点数为 $0/1/2$ 时,分别会多走 $u$,$\emptyset$,$v$
- 在考虑上一条多走的情况下,如果 $v$ 最后被关闭了,那么还需要在中间走一个 $u-v$ 补一下。
考场上,除了看出来是个 DP,其它都没有看出来。
- 注意树上路径 dp 可以采用记录端点个数。但是要小心处理单个点的情况。
- 注意如果方便的话优先处理掉没有用的部分,因为它们可能对答案造成干扰。
- 注意 dp 初值取 $\min$ 或 $\max$ 的时候考虑 $\inf$ 和 $-\inf$
- 转移要注意状态的严谨性,以及举几个例子来验证。
1 |
|
T2
一段区间的权值为 $len\times \min{a}\times \min{b}$,求最大的权值
分治,计算出所有三元组(到中点的距离,到中点的 $\min{a}$,到中点的 $\min{b}$),考虑合并。首先考虑两个 $\min$ 都在同一边取到的情况,此时另一边只需要让长度尽量大即可,容易单调扫描出另一边的合法区间。不在同一边的情况,同样可以单调扫描出另一边的合法区间,不妨设 $\min{a}$ 在左边取到,那么两个三元组会产生贡献 $(L+R)\cdot ma_l\cdot mb_r$,其中 $(L+R)\cdot mb_r$ 相当于一次函数最值,可以通过线段树维护凸包的方式快速计算。直接计算是三个 $\log$ ,但是注意 $L$ 是单调的,所以线段树上每个凸包的最优解都是单调移动的,这样就可以去掉一个 $\log$
如何用线段树维护凸包?只需要在每个线段树的节点开一个栈,保存这个线段树节点所代表的区间中的所有点的凸包即可。然后本来是要在上面二分的,但是因为具有单调性,可以用指针扫。
如何想到分治,只需要考虑答案是 $len\times ma\times mb$,而最值和区间都是分治的常见套路。
1 | struct Point{ |
T3
考虑大部分点的 lca 都是在分叉点上,除非在一条链上,我们考虑只保留分叉点和其儿子之间的连边,其余都缩成一个点,首先点数是 $O(n)$ 的,而且我们只需要知道每个点缩点之后是哪个点,新树上两个点的 lca 是什么就可以了。
整个过程可以用可持久化线段树从下往上做。
1 | int n,q,t,a[N],b[N],mod,c[N<<2]; |