[SDOI 2017] 苹果树

一些闲话:前排真的超级热热热热热热热热热热热热热热热热热热。要热死了要热死了要热死了 ☹️😖😵‍💫。

神奇背包。

可以发现 \(t-h\leqslant k\) 是一个非常辣手的限制,有了它至少需要记录选取的最深深度和 \(t\),这就直接有 \(n^2\) 的空间复杂度了。所以考虑用一些奇怪的手段把它优化掉。

考察树形依赖限制,可以发现在一个点取苹果后,至少要在它到根的路径上每一个点中取一个苹果,这就和深度挂上了钩。那么题意实际上转化成了钦定一个点作为选取点中深度最深的点,它向上到根的链所包含的点必选且 选一次 不计入苹果个数,其它的点(当然也包含链上的点,只是个数 \(a_i'=a_i-1\))不能选超过 \(k\) 个。

另外也可以发现,钦定的点一定是叶子节点,因为向下延伸可以无花费地增加一个苹果。

以这条链为分界线,可以将这棵树分为三部分:链左侧,链上,链右侧。事实上可以用 \(\rm dfs\) 序来考虑这个问题,算出链左侧与链右侧的 \(\mathtt{dp}\) 值,再枚举叶子节点把它们拼在一起。

这里以链左侧为例 —— 令 \(dp(i,j)\) 为按 \(\rm dfs\) 序考虑到 \(i\),体积为 \(j\) 的最大收益,并假定 \(i\) 到根的链就是最终选择的链。所以对于 \(u\rightarrow v\) 的父子关系,首先将 \(u\)\(\mathtt{dp}\) 值传给 \(v\),然后 \(v\) 加入 \(a_v-1\)\(v\) 上的苹果;等 \(\mathtt{dp}\)\(v\) 这棵子树后进行回传,加入 \(1\)\(v\) 上的苹果,因为此时 \(v\) 一定不在链上了,这里 需要注意的是,这一个苹果是强制加入的,为了满足树形依赖限制。前一个 \(\mathtt{dp}\) 可以单调队列优化,所以复杂度是 \(\mathcal O(k)\) 的。

对于链右侧,需要先将之前的边倒序遍历。其次需要在回退的时候才加入 \(a_u-1\)\(u\) 上的苹果,这样才能和链右侧恰好拼起来。

P6326 Shopping

一些闲话:依稀记得之前做过一道类似的题,但是怎么都找不到了 🥲。

\(\text{Update}\):找到那篇博客了(就是这道题),竟然还是 \(2\) 年前写的。那时候还在 \(\rm csdn\) 上呢。

首先题目限制实际上可以转化为选一个连通块,于是有一个 \(\mathcal{O}(nm^2)\)\(\tt dp\):令 \(dp(i,j)\) 为以 \(i\) 为子树(必选 \(i\)),花费为 \(j\) 的最大价值。每个连通块都在它深度最浅的点上计数了。可以发现,背包的瓶颈在于两个背包的合并是 \(\mathcal O(m^2)\) 的。

插入一个元素可以用单调队列做到 \(\mathcal O(m)\),所以我们尝试用 dfs 序考虑这个问题。但是用 dfs 序也就意味着只能考虑 dfs 序为 \([1,i]\)\([i,n]\) 的一段区间,不妨就考虑 \([1,i]\) 区间,我们无法求出某一个子树的贡献,只能算出根节点(也就是 dfs 序为 \(1\))的贡献,且时间复杂度为 \(\mathcal O(nm)\).

于是可以想到点分治。复杂度降到 \(\mathcal O(nm\log n)\).

CF1286E Fedya the Potter Strikes Back

一些闲话:🏊🏻🧊☁️ 讲的 \(\text{q-}\)模拟根本听不懂啊……自闭了。

首先考虑将区间右端点移动到 \(r\) 对可疑度之和的增量,实际上就是做一个 \(\tt{kmp}\),从 \(r\) 开始不断跳 \(\rm nxt\) 进行统计,不过这样做肯定是会 TLE 的。考虑维护当前末尾不断跳 \(\rm nxt\) 形成的集合 \(S\),同时维护这个集合的可疑度之和 \(w\)。把集合中的元素编号成 \(s_1,s_2,\dots, s_k\),将右指针移到 \(r\) 时,对集合做出如下操作:

  • 如果 \(\bold{str}(s_i+1)\ne \bold{str}(r)\),需要从集合中删除此元素,同时还需要维护 \(w\)
  • 如果 \(\bold{str}(1)=\bold{str}(r)\),可以向集合中加入元素。

最后,需要把在集合中的元素的可疑度与 \(w_r\)\(\min\).

如何快速删除元素呢?维护 \(\text{dif}(u)\) 表示离 \(u\) 最近的 \(\tt kmp\) 树上的 祖先 \(v\),满足 \(\bold{str}(u+1)\ne \bold{str}(v+1)\),这个函数可以在拓展到 \(i+1\) 时递推第 \(i\) 项。利用 \(\text{dif}(u)\) 进行跳跃,每次复杂度就是后一位与 \(\bold{str}(r)\) 不同的集合元素个数,而且它们被遍历后就会被删除。同时,由于每次至多增加一个集合元素,所以均摊复杂度是 \(\mathcal{O}(n)\) 的。

维护 \(w\) 是经典的,可以做一个单调栈 + 二分来定位当右指针为 \(r\) 时,区间 \([i,r]\) 的可疑度。

如何与 \(w_r\)\(\min\) 呢?直接用 map/set 维护 \((\)可疑度\(\text{, }\)元素个数\()\),暴力修改即可。因为每种权值只有可能被取 \(\min\) 一次,所以复杂度是对的。总复杂度 \(\mathcal O(n\log n)\).

posted on 2022-07-13 11:29  Oxide  阅读(130)  评论(4编辑  收藏  举报