<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Trees |</title><link>https://sichen-wang.github.io/tags/trees/</link><atom:link href="https://sichen-wang.github.io/tags/trees/index.xml" rel="self" type="application/rss+xml"/><description>Trees</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sat, 22 Jun 2024 15:11:24 +0000</lastBuildDate><image><url>https://sichen-wang.github.io/media/icon_hu_9dfcb674aa885f38.png</url><title>Trees</title><link>https://sichen-wang.github.io/tags/trees/</link></image><item><title>树上背包</title><link>https://sichen-wang.github.io/blog/%E6%A0%91%E4%B8%8A%E8%83%8C%E5%8C%85/</link><pubDate>Sat, 22 Jun 2024 15:11:24 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E6%A0%91%E4%B8%8A%E8%83%8C%E5%8C%85/</guid><description>&lt;h2 id="选取-m-个结点"&gt;选取 m 个结点&lt;/h2&gt;
&lt;p&gt;这是最普遍的情况, 从树中选取 \(m\) 个结点, 最大化它们的价值之和.&lt;/p&gt;
&lt;p&gt;符合直觉地, 设 \(f_{u, i}\) 表示从以 \(u\) 为根的子树中选取了 \(i\) 个结点的最大价值之和. 转移是显然的:&lt;/p&gt;
\[
f_{u, i + j} = \max\{f_{u, i} + f_{v, j}\}
\]&lt;p&gt;其中 \(i\), \(j\) 的范围应当分别为 \(u\) 此前枚举的子树大小和, 以 \(v\) 为根的子树大小.&lt;/p&gt;
&lt;p&gt;其最优性和可行性都是显然的, 我们考虑这个算法的复杂度. 看起来似乎是 \(\Theta(n^{3})\), 但事实上对于任意点对 \((i \in S_{u}, j \in S_{v})\), 它只会在 \(u\) 处被枚举一次. 于是时间复杂度实际上是 \(\Theta(n^{2})\).&lt;/p&gt;
&lt;h2 id="选取结点的代价之和至多为-m"&gt;选取结点的代价之和至多为 m&lt;/h2&gt;
&lt;p&gt;在这个问题中为每个结点引入了代价, 此时上述的复杂度分析不再适用.&lt;/p&gt;
&lt;p&gt;我们不妨考虑换一种思路, 正常的 \(0/1\) 背包复杂度之所以为 \(\Theta(nm)\), 是因为每次只需要对一个物品做是否选取的决策. 在这里, 我们同样考虑将物品独立起来, 只考虑当前物品选或不选. 为了保证无后效性, 接下来的结点编号都被重新设为其在后序遍历中的时间戳.&lt;/p&gt;
&lt;p&gt;设 \(f_{i, j}\) 表示考虑了前 \(i\) 个物品, 背包大小为 \(j\), 能取到的最大价值和.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若选该物品, 则可以选择它子树中的物品, \(f_{i, j} \leftarrow f_{i - 1, j - w_{i}} + v_{i}\).&lt;/li&gt;
&lt;li&gt;若不选该物品, 则它子树内的物品都不可以选, 而子树中的编号恰好是连续的, 于是 \(f_{i, j} \leftarrow f_{i - siz_{i}, j}\).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样转移时间复杂度即为 \(\Theta(nm)\).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nl"&gt;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;knapsack_on_tree&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;siz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>「Codechef」Children Trips</title><link>https://sichen-wang.github.io/blog/codechef-children-trips/</link><pubDate>Sat, 24 Jun 2023 11:00:56 +0000</pubDate><guid>https://sichen-wang.github.io/blog/codechef-children-trips/</guid><description>&lt;h2 id="description"&gt;Description&lt;/h2&gt;
&lt;p&gt;你在一颗树上旅行。&lt;/p&gt;
&lt;p&gt;树由 \(n\) 个点，\(n - 1\) 条边构成，每条边的长度 \(w\) 是 \(1\) 或 \(2\)。&lt;/p&gt;
&lt;p&gt;你要从点 \(u\) 沿着唯一的简单路径走到点 \(v\)。但是，你的体力有限，所以一天之内最多只能走 \(l\) 的距离。一天结束时待在树的节点外是很危险的，所以你必须在一天结束前到达某个节点并停下（可以刚好到达），即使你没有走到 \(l\) 的距离。&lt;/p&gt;
&lt;p&gt;给定这棵树和 \(q\) 个询问，每个询问给出 \(u,v,l\)，请求出至少需要多少天。&lt;/p&gt;
&lt;p&gt;数据范围 : \(1 \leqslant n,q \leqslant 10^{5}, 1 \leqslant x,y,u,v \leqslant n,w \in \{1, 2\}, 2 \leqslant l \leqslant 2n.\)&lt;/p&gt;
&lt;h2 id="tutorial"&gt;Tutorial&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Lemma1:&lt;/strong&gt; 一条路径，正着走和倒着走答案是一样的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proof1:&lt;/strong&gt; 考虑将正着和倒着每天累计走的距离写下来，容易发现正着走相当于一开始落后了至多 \(1\) 的距离，后面在不断追赶。可以发现在走的过程中是存在单调性的，所以正着走一定不可能超过倒着走，但也不可能落后超过 \(1\)。由于最后会走到相同的位置，所以答案是一样的。&lt;/p&gt;
&lt;p&gt;有了上述引理，我们就可以考虑分别计算 \(u\) 和 \(v\) 分别跳到 \(\textrm{LCA}(u, v)\) 下面最高能跳到的点的答案。设 \(l_{1}, l_{2}\) 分别表示 \(u\) 和 \(v\) 剩下的距离，最终答案即为 \(u\) 和 \(v\) 的答案之和加上 \(\left\lceil\frac{l_{1} + l_{2}}{l}\right\rceil\)。&lt;/p&gt;
&lt;p&gt;考虑对询问根号分治，分别处理 \(l \leqslant \sqrt{n}\) 的询问和 \(l \gt \sqrt{n}\) 的询问。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于 \(l \gt \sqrt{n}\) 的询问，可以发现其跳的次数不超过 \(\sqrt{n}\)，于是可以直接暴力跳，用倍增维护一下即可。&lt;/li&gt;
&lt;li&gt;对于 \(l \leqslant \sqrt{n}\) 的询问，可以预处理出从每个点 \(u\) 开始，此时的 \(l = k\)，往上跳 \(2^{i}\) 天到的点 \(f_{u, k, i}\)，倍增往上跳即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;时间复杂度 \(\Theta(n \sqrt{n} \log n)\)，卡一卡常可以通过。&lt;/p&gt;
&lt;p&gt;考虑换一种思路，我们给树上 \(\sqrt{n}\) 个点打上标记，称它们为特殊点。那么如果标记打得足够均匀，就可以使 \(u, v \to \textrm{LCA}(u, v)\) 的路径上每隔 \(\sqrt{n}\) 的距离经过一个特殊点，且总共经过 \(\sqrt{n}\) 个特殊点。至于如何打标记，可以记 \(dis_{u}\) 表示 \(u\) 到树上最远点的距离，取 \(B = \sqrt{n}\)，\(u\) 为标记点当且仅当 \(B | dis_{u}\)。&lt;/p&gt;
&lt;p&gt;考虑预处理 \(f_{u, k}\) 表示当 \(l = k\) 时，从 \(u\) 开始走一天到的点（如果这个点超过了 \(u\) 祖先中最深的特殊点，那么就将 \(f_{u, k}\) 设为该特殊点，并且计算剩下了多少距离），\(g_{u, k}\) 表示当 \(l = k\) 时，从 \(u\) 开始走到 \(u\) 祖先中最深的特殊点需要花费的天数。&lt;/p&gt;
&lt;p&gt;容易发现，由于走到 \(u\) 祖先中最深的特殊点最多 \(2\sqrt{n}\) 的距离，所以 \(k\) 的取值范围为 \([0, 2\sqrt{n}]\)。预处理直接从上往下递推即可，由于状态总数是 \(n \sqrt{n}\) 的，所以预处理时间复杂度也是 \(\Theta(n \sqrt{n})\)。至于如何使用这两个数组优化往上跳的过程则是简单的，不作赘述。&lt;/p&gt;
&lt;p&gt;总时间复杂度 \(\Theta(n \sqrt{n})\)，可以轻松通过此题。&lt;/p&gt;</description></item><item><title>虚树</title><link>https://sichen-wang.github.io/blog/%E8%99%9A%E6%A0%91/</link><pubDate>Sat, 24 Jun 2023 11:00:56 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E8%99%9A%E6%A0%91/</guid><description>&lt;h2 id="虚树"&gt;虚树&lt;/h2&gt;
&lt;p&gt;在一些问题中，我们只关心关键点的信息，同时我们需要维护他们之间的树形结构，于是可以想到将它们和它们之间的 \(\rm LCA\) 拉出来建一颗树，这棵树就被称作虚树。&lt;/p&gt;
&lt;p&gt;有一个朴素的想法，就是对它们两两求 \(\rm LCA\)，并且对求出的 \(\rm LCA\) 再求 \(\rm LCA\)，中途判重，最后按照祖先关系连边。&lt;/p&gt;
&lt;p&gt;经过观察可以发现，我们只需要按照 \(\rm dfs\) 虚从小到大的顺序枚举每个点，将相邻两点求 \(\rm LCA\) 即可。具体来说，我们可以维护一个栈，这个栈中存的是当前点在虚树上的所有祖先。设当前栈顶为 \(v\)，对于新加入的结点 \(u\)，我们对它进行分类讨论 ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若 \(\rm LCA(u,v)=v\)，那么直接将 \(u\) 入栈。&lt;/li&gt;
&lt;li&gt;若 \(\rm LCA(u,v)\) 是栈中某个不为 \(v\) 的点，则弹栈直到 \(\rm LCA(u,v)\)，每弹一个就向栈中比它深度多 \(1\) 的结点连边，最后并把 \(u\) 入栈。&lt;/li&gt;
&lt;li&gt;若 \(\rm LCA(u,v)\) 不在栈中，那么弹栈直到栈顶的 \(\rm dfs\) 序小于 \(\rm LCA(u,v)\) 的 \(\rm dfs\) 序，每弹一个就向栈中比它深度多 \(1\) 的结点连边，并把最后一个弹出的结点向 \(\rm LCA(u,v)\) 连边，最后把 \(\rm LCA(u,v)\) 和 \(u\) 入栈。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不难发现这样一定是对的，并且设关键点数量为 \(k\)，则虚树内点数不超过 \(2k\)。&lt;/p&gt;
&lt;p&gt;在一棵有 \(n\) 个点的树上建立一颗有 \(k\) 个点的虚树的时间复杂度为 \(\Theta(k\log n)\)。&lt;/p&gt;
&lt;h2 id="经典例题"&gt;经典例题&lt;/h2&gt;
&lt;h3 id="sdoi2011-消耗战"&gt;[SDOI2011] 消耗战&lt;/h3&gt;
&lt;p&gt;首先有一个暴力 \(\rm DP\)，设 \(dp_{u}\) 表示将 \(u\) 的子树内所有关键点与 \(u\) 的联系断开所需要的最小代价。转移时枚举 \(u\) 的所有子节点，分类讨论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若 \(v\) 为关键点，那么必须切断这条边，有 \(dp_{u}=dp_{u}+w_{u,v}\)&lt;/li&gt;
&lt;li&gt;若 \(v\) 不为关键点，那么可以切断这条边也可以从 \(dp_{v}\) 转移，故有 \(dp_{u}=dp_{u}+min\{dp_{v},w_{u,v}\}\)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终答案就是 \(dp_{1}\)，这个暴力的时间复杂度是 \(\Theta(qn)\)。&lt;/p&gt;
&lt;p&gt;观察到 \(\sum k\leqslant 5e5\)，所以考虑对每次询问建虚树。&lt;/p&gt;
&lt;p&gt;建虚树之前需要记 \(M_{u}\) 表示从 \(1\) 到 \(u\) 的路径上最短的边权，因为只需要切掉最短的边权就可以让点 \(u\) 与 \(1\) 不连通，而切上面的边是更优的，所以可以用 \(M_{u}\) 直接替换转移方程中的 \(w_{u,v}\)。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(\sum k\log n)\)。&lt;/p&gt;
&lt;h3 id="heoi2014-大工程"&gt;[HEOI2014] 大工程&lt;/h3&gt;
&lt;p&gt;首先建虚树。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于两两之间距离之和，可以计算每条边的贡献。&lt;/li&gt;
&lt;li&gt;对于最大\(/\)最小值，可以树形 \(\rm DP\) 或点分治。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;时间复杂度 \(\Theta(\sum k\log n)\)。&lt;/p&gt;
&lt;h3 id="sdoi2015-寻宝游戏"&gt;[SDOI2015] 寻宝游戏&lt;/h3&gt;
&lt;p&gt;我们发现如果将虚树建出来，那么答案就是虚树上所有边权之和的两倍。&lt;/p&gt;
&lt;p&gt;于是我们考虑动态维护虚树的边权之和。先把所有点的 \(\rm dfs\) 序求出来，然后我们发现边权之和等于 \(\rm dfs\) 序相邻两点的距离之和加上最左边和最右边两点的距离，于是我们可以使用 \(\rm set\) 维护，树剖求 \(\rm LCA\)。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\rm \Theta(n\log n)\)。&lt;/p&gt;</description></item><item><title>长链剖分</title><link>https://sichen-wang.github.io/blog/%E9%95%BF%E9%93%BE%E5%89%96%E5%88%86/</link><pubDate>Sat, 24 Jun 2023 11:00:56 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E9%95%BF%E9%93%BE%E5%89%96%E5%88%86/</guid><description>&lt;h3 id="长链剖分"&gt;长链剖分&lt;/h3&gt;
&lt;p&gt;考虑将重儿子设为链最长的那一个，剖分是简单的，可以做到 \(\Theta(n).\)&lt;/p&gt;
&lt;p&gt;这样剖分有一些性质：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;链长和是 \(n\)，因为每个点都在且仅在一条链中。&lt;/li&gt;
&lt;li&gt;任意点 \(x\) 的 \(k\) 级祖先 \(y\) 到它所在的长链底端距离不小于 \(k\) 。因为如果 \(x\) 和 \(y\) 在同一条长链上，那么 \(y\) 所在的长链长度不小于 \(k\) 。如果它们不在同一条的长链上，那么 \(y\) 到另一条长链底端的距离一定大于 \(k\)，否则的话 \(x\) 所在的链就可以接在 \(y\) 上成为更长的链。&lt;/li&gt;
&lt;li&gt;从任意一个点开始跳重链的次数最多是 \(\sqrt{n}\) 级别的。因为容易知道每次跳到的长链长度一定大于当前链，于是最坏情况是分别经过了长度为 \(1, 2, 3, \cdots, \sqrt{n}\) 的长链，最多跳 \(\sqrt{n}\) 次。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="thetan-log-n---theta1-算-k-级祖先"&gt;Theta(n log n) - Theta(1) 算 k 级祖先&lt;/h3&gt;
&lt;p&gt;考虑预处理每个点的 \(2\) 的幂次级祖先，对于一次询问 \((u, k)\)，首先跳到 \(u\) 的 \(highbit(k)\) 级祖先 \(v\) 上，由长链剖分的性质可知，\(v\) 到其所在长链底端的距离不小于 \(highbit(k).\)&lt;/p&gt;
&lt;p&gt;由于长链长度之和为 \(n\)，所以我们可以预处理每条链顶端节点的 \(l\) 级祖先，\(l\) 取遍不大于链长的所有整数。并且我们还可以存下每条链的所有节点，挂在链顶。&lt;/p&gt;
&lt;p&gt;这样，对于一次询问，假设 \(v\) 的 \(k - higtbit(k)\) 级祖先不超过链顶，那么可以直接查询，否则也可以从链顶跳若干步得到。由于 \(k - highbit(k) \lt hightbit(k)\)，故其一定小于链长，要查询的祖先是预处理过的。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(n \log n)\) 预处理，单次查询 \(\Theta(1)\)。&lt;/p&gt;</description></item></channel></rss>