ZJOI2019 语言
2020-12-13 03:55
标签:can modify log class hup get 路径 实现 lin 若城市 \(u,v\) 能够开展贸易,则称 \(u\) 可以到达 那么不难发现某个点能到达的所有点连通 如果路径 \(s \to t\) 包含点 \(u\),\(s,t\) 则是 \(u\) 的两个极远点,那么 \(u\) 的生成树为连通 \(u\) 的所有极远点的最小生成树 于是,我们需要事先思考子问题:给定树上若干的点,如何求最小生成树大小? 这应该是个经典问题。可能要用到一点建虚树的思想。 为了方便,我们硬点存在极远点 111 ,最后再计算其影响。 我们给这些点按照 dfs\mathrm{dfs}dfs 序排序,然后一个一个地加进去。假设当前加入 uuu 号点,之前加入的点构成点集 SSS ,SSS 的最小生成树是 TTT。显然,为了使 uuu 和 TTT 连通,只需要找到 TTT 中离 uuu 最近的点连起来就好了,这“最近的点”正是 SSS 中的某个点与 uuu 的 lca\mathrm{lca}lca 。如果你对 dfs\mathrm{dfs}dfs 序有较好的感觉,其实所谓 SSS 中的某个点,就是上一个加进去的点 vvv !所以 uuu 的贡献是 depu?deplca(u,v)\mathrm{dep}u - \mathrm{dep}{\mathrm{lca}(u,,v)}depu??deplca(u,v)? 。别忘了硬点了 111 号点,最后还要减 dep所有点的 lca\mathrm{dep}_{\text{所有点的}?\mathrm{lca}}dep所有点的 lca? 。 上面那段可能有点绕,强烈建议画个图感受一下! 暴力加点似乎不容易被利用,此时最擅长分治的线段树终于重磅登场了。 仍然是以 dfs\mathrm{dfs}dfs 序为下标,线段树的叶子结点控制原树上每个点选或不选,每个结点表示了硬点 111 后一段区间的点集的最小生成树大小,并存下每个点集中下标最小和最大的点。类似地,pushup\mathrm{pushup}pushup 时要减去 deplca(u,v)\mathrm{dep}{\mathrm{lca}(u,,v)}deplca(u,v)? 。此时的 uuu 当然是左孩子已选下标最大的,vvv 当然是右孩子已选下标最小的。查询的话只要用根结点的答案减去 dep所有点的 lca\mathrm{dep}{\text{所有点的}?\mathrm{lca}}dep所有点的 lca? 即可。 白白套一个线段树不是多 log?\loglog 吗?别急,正解已经浮出水面了。 想象每个结点都有一棵线段树。注意到有一条路径 s→ts \to ts→t ,我们会给该路径上的每棵线段树都选上 s,ts,,ts,t 两点。按照套路,求出 lca=lca(u,v)\mathrm{lca} = \mathrm{lca}(u,,v)lca=lca(u,v) ,等同于 s→lca,t→lcas \to \mathrm{lca},,t\to \mathrm{lca}s→lca,t→lca 两条链上执行线段树修改。仍然是套路,链上修改可以转换成树上差分打标记,s,t,lca,fa[lca]s,,t,,\mathrm{lca},,\mathrm{fa}[\mathrm{lca}]s,t,lca,fa[lca] 分别打上 1,1,?1,?11,,1,,-1,,-11,1,?1,?1 。 慢着……线段树打标记是可以,但每个结点要把自己的信息继承给父亲,这怎么做? 至此,[ZJOI2019]语言 的大致做法讲完了。nnn 次线段树合并是 O(nlog?n)O(n \log n)O(nlogn) 的,而 nnn 次修改要求 nlog?nn \log nnlogn 次 lca\mathrm{lca}lca ,如果树剖或倍增,复杂度是 O(nlog?2n)O(n \log^2 n)O(nlog2n) ,如果使用欧拉序 st\mathrm{st}st 表,复杂度是优美的 O(nlog?n)O(n \log n)O(nlogn) 。 刚才求的 (u,v)(u,,v)(u,v) 没有强制 u ZJOI2019 语言 标签:can modify log class hup get 路径 实现 lin 原文地址:https://www.cnblogs.com/wawawa8/p/11094612.htmlZJOI2019 语言
动态开点 + 线段树合并!
代码实现#include