20240806:点分治,虚树选做

P4178 Tree#

题意:给定一棵树,求多少无序对 (u,v) 满足 dist(u,v)k

对于树上的路径进行分类:经过根;不经过根。

第二类路径点可以通过递归子树求出。

对于经过根的路径,可以一遍 dfs 求出每个点到根的距离 dis(u)

问题转化为求 dis(u)+dis(v)ku,v 不在同一棵子树的点对数。

如果没有后面子树的限制,可以简单的排序 + 双指针求出,那么只要把每棵子树多算的减掉即可。

单次复杂度 O(nlogn)。如果直接递归,复杂度高达 O(n2logn)

考虑 rt 选取当前树的重心(最大子树最小)。

rt 的每棵子树大小不大于 n/2,如果存在子树 u 大于 n/2,以 u 为重心不会比 rt 更劣。

因此每次都选重心,树的大小至少减少一半,最多递归 O(logn) 层,每层总结点数 O(n)

时间复杂度 O(nlog2n)submission

P9058 [Ynoi2004] rpmtdq#

题意:对于一棵树有 q 次询问:给定 l,r,求 minli<jrdist(i,j)

总共 O(n2) 个点对,考虑哪些一定不可能成为答案。

如果 (x1,y1), (x2,y2) 满足 x1x2<y2y1dist(x2,y2)dist(x1,y1)

那么对于任何询问,选 (x2,y2) 一定不劣于选 (x1,y1),我们称 (x2,y2)有效的。

点分治处理路径问题,只统计经过 rt 的有效点对 (i,j)(不妨钦定 dist(i,rt)dist(j,rt))。

设当前在处理点 u,哪些不在同一子树中的点 v 会与 u 组成有效点对。

定义 preu 表示满足 dist(v,rt)dist(u,rt) 的小于 u 的最大 v

现在证明为什么 (v,u), v<preu 是没用的。

对于 v<preu,有

dist(v,preu)dist(v,rt)+dist(preu,rt)dist(v,rt)+dist(u,rt)=dist(v,u)

显然 (v,u) 对于 (v,preu) 而言是无效的,与假设矛盾。

定义 nxtu 表示满足 dist(v,rt)dist(u,rt) 的大于 u 的最小 v。同理证明 (u,v), v>nxtu 是没用的。

总结:任意点 u 只有 (preu,u)(u,nxtu) 是有效的。

但是 (v,u) 还要求在不同子树,假设 preu 恰与 u 在同一子树,只会使得 dist(preu,u) 变得更小,因此不需要考虑子树限制。

u 一次只产生 O(1) 个点对,因此整个分治过程产生 O(nlogn) 个点对。

将询问离线,转化为二维数点,时间复杂度 O(nlog2n)

点对 (i,j) 的权值 dist(i,j) 可以直接用 dist(i,rt)+dist(j,rt),这样带来的问题是 i,j 在同一子树的距离是错误的。

我们总能递归到 (i,j) 经过的一个重心,在这个中心上一定能正确的求出 (i,j) 距离或者产生更优点对。

还有一个问题是如何求前驱后继,对于 P9678 来说,用 set 维护足矣,但本题还需进一步卡常。

d(u)=dist(u,rt),将二元组 (u,d(u)) 根据 u 排序。维护一个 d 值单调不降的单调栈,可以求出所有前驱。后继同理。

submission

P4292 [WC2010] 重建计划#

题意:给定一棵树,求长度属于 [L,U] 的路径的最大价值,路径 S 的价值定义为 eSw(e)|S|

对于一条路径,如果 eS(w(e)avg)0,说明这条路径的价值一定大于等于 avg。

不难想到二分答案,把每条边都减去 mid 后检查长度属于 [L,U] 的最大路径和是否非负。

还是通过经过哪个重心来划分路径,设当前重心为 rt

fi 表示在已经遍历完的子树里深度为 i 的点到根的最长距离, gi 表示在当前子树里深度为 i 的点到根的最长距离。

显然用 maxj[iU+L, i]fj+gUi 去更新答案。

前面一项很容易用数据结构维护,但是加上点分治和二分复杂度有三个 log,无法通过。

发现 f 的答案区间是一个单调队列的形式,时间复杂度 O(当前子树深度 + 之前出现过的最大子树深度)

这样复杂度还是可能退化到 O(n2),但是如果按深度从小到大枚举子树,统计答案这一步就是线性的。

如果直接点分治的同时去排序,仍然是三个 log 的。但是点分树的形态始终不变,我们可以在二分之前对于每个重心先排好序。

这样整体就是双 log 复杂度。submission

CF150E Freezing with Style#

题意:给定一颗带边权的树,求一条边数在 [L,R] 之间的路径,并使得路径上边权的中位数最大。输出一条可行路径的两个端点。

对于序列 a,定义 bi={1aimid1otherwise,如果满足 bi>0,则 a 的中位数一定不大于 mid。

和上题做法一致,二分答案,如果存在路径满足 bi<0,说明答案还能变大。

val 为使所有合法路径 bi0 的最小值,那么所求答案即 mid = val - 1 时使 bi 最小的路径两端。

subsmissin

CF1260F Colored Tree#

题意:

给定一棵树,每个节点有一个颜色 hhi[li,ri] 内的一个整数。

对于全部 M=(rili+1) 种不同的染色方案,求:

hi=hj,1i<jndist(i,j)(mod109+7)

dist(i,j) 对答案的贡献有 (d(i,rt)+d(j,rt))×|HiHj|×ki,j(rili+1)

不妨只考虑交集中的某一点 x 对答案的贡献:

w(i,j)+w(i,k)=(di+dj)×MLj×Li+(di+dk)×MLk×LidiLi×(1Lj+1Lk)+1Li×(djLj+dkLk)M 每项都有,可以最后再乘

线段树维护交集贡献,时间复杂度 O(nlog2n)

懒标记线段树爆了,考虑树状数组维护区间加区间和。

维护差分数组 biai=bi×(ni+1)=(n+1)×bibi×i

后面一个和式也用树状数组维护即可。submission

[HZOI 2015] 树黑白#

题意:给定一棵树,一开始都是白色,支持两种操作:

  • u 反色。
  • 查询 u 到所有黑色节点的距离和。

u 的路径按照经过哪个重心分成 O(logn) 类。

因此不管修改还是查询都只要在点分树上暴力跳 logn 次。

fa(x) 表示 x 在点分树上的父亲节点,定义 x 的子树为以 x 为分治中心时的子树。

fx 表示 x 子树内的黑点到 x 的距离和,gx 表示 x 子树内的黑点到 fa(x) 的距离和,cntx 表示 x 子树内的黑点数。

x 一直跳到点分树的根,假设当前点是 cur,上一个点是 prefa(pre)=cur):

那么 cur 对询问 u 的贡献有

fcurgpre+(cntcurcntpre)×dist(u,cur)

submission

P2056 [ZJOI2007] 捉迷藏#

题意:给定一棵树,初始全黑。支持单点改色,询问最远两个黑点距离。

类似直径求法,每个分治重心维护子树内黑点到 rt 的最大值与次大值,可删堆维护。

mutiset 常数过大了,手写一个懒删除堆。submission

P3345 [ZJOI2015] 幻想乡战略游戏#

题意:给定一棵树,保证每个点度数不超过 20。单点修改点权 ai,每次查询最小的 f(u)=v=1ndist(u,v)×av

考虑暴力做法:

设当前在点 uu 表示 u 子树内的点权和,=i=1nai

与之直接相连的儿子 vu 更优当且仅当 dist(u,v)×(2v)<0(考虑答案的变化量)。

也就是 2v>,如果存在儿子节点更优,那么只可能有一个 v 满足条件(2v>u)。

  • f(v)f(u)

vv 子树中的一点。

由于 是常量,且 vv,因此从 u 走到 v 只会使答案越来越大。

因此 v 的子树中不存在比 u 更优的点。

  • f(v)<f(u)

    v 为最优决策点。

    显然 vv 的子树内,现在证明不管从 v 子树的哪个点 x 出发(将 f(x)x 的儿子比较)都能到达 v

    砍掉多余部分,只留 v 的子树。

    强制使 x 为根,由于 2v>,一定有 2fa(v)>,因此存在一条 vx 的决策路径。

修改和单点查 f 可以用点分治轻而易举做到 O(logn),瓶颈在与上述算法最坏会达到单次 O(nlogn)

一个想法是枚举 x 的儿子 y(原树),如果 f(y)<f(x),说明最优决策点在 y 的分治子树中,递归到包含 y 的儿子(点分树)。

时间复杂度 O(20log2n),正确性可以由上述第二点得到。

加强版少去了度数限制,做法是链剖 + 线段树,待补。

submission

P2495 [SDOI2011] 消耗战#

题意:给定一棵树,m 次询问:给出 k 个关键点,求使每个点都不能到的最根小代价(花费 w(u,v) 使 (u,v) 断掉)。

设关键点集为 S

显然有 O(n) 的树形 dp,fx 表示使 x 内关键点都不能到根的最小代价:

fx={w(x,fa(x))xSmin(w(x,fa(x)), yson(x)fy)otherwise

仅保留关键点之间的祖先后代关系(保留根节点,和关键点两两之间的 lca)不会改变最后的 dp 值。

fx={x 与在虚树中的父亲之间的最小边权,倍增解决xSmin(w, yson(x)fy)otherwise

定义虚树为包含关键点和所有 lca 的最小树。

以下构造方式能说明虚树规模只有 O(k),如果能快速建出虚树即可解决本题。

二次排序 + LCA 连边

  • 将关键点按 DFS 序排序;
  • 遍历一遍,任意两个相邻的关键点求一下 LCA,并且判重;
  • 然后根据原树中的祖先后代关系建树。

具体实现上,在关键点序列上枚举相邻的两个数,两两求得 LCA 并且加入序列 A 中。

此时 A 一定包含了虚树中的所有点(可能重复)。

假设 a,b,c 按照 dfs 序依次递增,则

lca(a,c)=lca(lca(a,b), lca(b,c))

由于 lca(a,b)lca(b,c) 都是 b 的祖先,因此其中一个一定是另一个的祖先。

假设按照时间戳排序得到 x1,x2xm

那么任意的两个节点的 lca 可以写做

lca(ai,aj)=lca(lca(ai,ai+1), lca(ai+1,ai+2), , lca(aj1,aj))

任意两个关键点的 lca 都包含在我们新增的相邻 lca 里。

同时证明了虚树规模是 O(k) 的。

A 按照 dfs 序排序并去重。枚举相邻的两个点 x,y,连接 lca(x,y)y,这样就完成了构造。

为什么这样连边不重不漏?

如果 xy 的祖先。

由于 x,yA 中相邻,因此 xy 的链上不存在任何其他节点,直接 x 连向 y 即可。

如果 x 不是 y 的祖先。

lca 的 dfs 序一定小于 x,因此 xlca 在之前已经直接或间接相连了。

又由于 x,y 相邻,lcay 之间不存在其他点,lca 连向 y 是不重不漏的。

submission

P3320 [SDOI2015] 寻宝游戏#

题意:每次新增或减少一个关键点,并询问包含所有关键点的生成子树的边权和 ×2

这颗生成子树的根一定是所有关键点的最近公共祖先,因为任意两点要求联通。

发现这与我们构建虚树的形式很像,可以单次 O(klogn) 得到整棵树的边权和。

但是本题并不保证 k 的量级。

Gym - 104128E#

题意:给定一颗树,初始全白,问全部染黑的最小代价。把 x 子树里与 x 距离为 i 的点全部染黑代价为 ai

f(x,d) 表示在以 x 为根的子树里把深度为 d 的点全部染黑的最小代价,答案为 f(root,)

f(x,d)=min(addep(x), yson(x)f(y,d))

对于每个深度建出虚树,时间复杂度 O(nlogn)

submission

posted @   Lu_xZ  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示