传送门
思路
先不考虑距离的限制,我们有转移方程:
\[dp_i = dp_j+p_i(dis_i-dis_j)+q_i
\]
其中,\(dis_i\) 表示根到 \(i\) 的距离
那么我们就有朴素的斜率优化模型:
\[\begin{aligned}
dp_i-q_i-p_idis_i&=dp_j-p_idis_j\\\\
x&=p_i\\
k&=-dis_j\\
b&=dp_j
\end{aligned}\]
但现在有了距离的限制,让我们感到十分棘手
于是 lby 大佬给出了一个树套树的做法 (之前说的让树套树吃灰寄了,终究是让自己成为讨厌的人)
我们先进行树链剖分,将树划分成不超过 \(log\ n\) 条链,并编号
然后建线段树,树上的每个结点代表一棵李超线段树(李超树上的结点需要动态开店)
当我们要求结点 \(u\) 的最小费用时,我们就从它所在的链往上跳,如果当前链的任意结点到 \(u\) 的距离都不超过 \(lim_u\) ,就在线段树区间 \(dfn[l]\) ~ \(dfn[r]\) 上的李超树查询最小值
注意:最后一条链虽然不能整条链满足 \(lim_u\) 的限制,但可能某一段还是可以满足的,所以需要二分出这个结点,再求一次最小值
求完最小费用后,我们就更新线段树,所有包含 \(dfn[u]\) 的线段树区间上的李超树都要进行更新(常规的树套树)
最后注意一个坑点:\(x\) 有可能为 \(0\) ,查询/修改李超树时初始区间应为 \([0,p_{max}]\)
复杂度为 \(O(nlog^3n)\),但因为跑不满+数据太水,最慢的点也只跑了 \(460ms\)
代码
#include
#include
#include
#include
#include
#include
#include
#include