首先考虑如果是序列怎么做,比较明显的dp,dp[i]表示i走到1的最少花费,则
dp[i]=min{dp[j]+(dis[i]−dis[j])∗p[i]+q[i]|j<i,dis[i]−dis[j]<=li[i]}
d
p
[
i
]
=
m
i
n
{
d
p
[
j
]
+
(
d
i
s
[
i
]
−
d
i
s
[
j
]
)
∗
p
[
i
]
+
q
[
i
]
|
j
<
i
,
d
i
s
[
i
]
−
d
i
s
[
j
]
<=
l
i
[
i
]
}
我们自然想到斜率优化,我就不推式子了qaq。但是有两个限定条件决定j的取值范围,我们只好cdq分治维护凸包+二分查找最优斜率。推广到树上也是类似的,只不过我们这回要cdq分治结合点分治了。因为是一棵有根树,我们每次找到重心后,先分治处理此次分治子树的根(下文中的根都指此意义)所在的子树,然后用重心到根的路径上的点来更新重心的其他子树的点的答案(为了方便维护凸包,我们想只往里加点,于是先把子树的所有点按dis[i]-li[i]从大到小排序,而dis[now]是逐渐递减的,我们就可以只往里加点,而不删点了),再分治处理其他子树内部的影响。
注意维护这个下凸壳时是从右往左加点的…所以写着就比较的奇怪
复杂度
O(nlog2n)
O
(
n
l
o
g
2
n
)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define ll long long
#define inf 1LL<<60
#define N 200010
#define pa pair<ll,int>
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,fa[N],sz[N],rt,sumsize,f[N],cnt,q[N];
ll w[N],pi[N],qi[N],li[N],dis[N],dp[N];
bool vis[N];pa a[N];
vector<int>son[N];
inline void dfs(int x){
for(int i=0;i<son[x].size();++i){
int y=son[x][i];dis[y]=dis[x]+w[y];dfs(y);
}
}
inline void dfs2(int x){
sz[x]=1;f[x]=0;
for(int i=0;i<son[x].size();++i){
int y=son[x][i];if(vis[y]) continue;
dfs2(y);f[x]=max(f[x],sz[y]);sz[x]+=sz[y];
}f[x]=max(f[x],sumsize-sz[x]);if(f[x]<f[rt]&&sz[x]>1) rt=x;//至少要分治多于一个点
}
inline void dfs3(int x){
a[++cnt]=make_pair(dis[x]-li[x],x);
for(int i=0;i<son[x].size();++i){
int y=son[x][i];if(vis[y]) continue;dfs3(y);
}
}
inline bool cmp(pa a,pa b){return a.first>b.first;}
inline double slope(int k1,int k2){return (dp[k1]-dp[k2])*1.0/(dis[k1]-dis[k2]);}
inline void solve(int x,int Size){
if(Size==1) return;
rt=0;sumsize=Size;dfs2(x);int gp=rt;
for(int i=0;i<son[gp].size();++i) vis[son[gp][i]]=1;//把gp的儿子都堵上
//cdq分治,先处理根x所在子树,注意把重心gp也划分到根x所在子树中
solve(x,Size-sz[gp]+1);
cnt=0;
for(int i=0;i<son[gp].size();++i) dfs3(son[gp][i]);
sort(a+1,a+cnt+1,cmp);int now=gp,h=1,t=0;//按dis[i]-li[i]从大到小给i排序。
//用gp到根x的链上的点更新gp子树中的点的答案
for(int i=1;i<=cnt;++i){
while(now!=fa[x]&&dis[now]>=a[i].first){
while(h<t&&slope(q[t],now)>=slope(q[t-1],q[t])) t--;
q[++t]=now;now=fa[now];
}int l=1,r=t-1;if(h>t) continue;//注意判空
while(l<=r){//二分查找最优解
int mid=l+r>>1;
if(slope(q[mid],q[mid+1])<pi[a[i].second]) r=mid-1;
else l=mid+1;
}int j=q[r+1];
dp[a[i].second]=min(dp[a[i].second],dp[j]+(dis[a[i].second]-dis[j])*pi[a[i].second]+qi[a[i].second]);
}for(int i=0;i<son[gp].size();++i) solve(son[gp][i],sz[son[gp][i]]);
}
int main(){
// freopen("a.in","r",stdin);
n=read();int tt=read();f[0]=n+1;
for(int i=1;i<=n;++i) dp[i]=inf;dp[1]=0;
for(int i=2;i<=n;++i){
fa[i]=read();son[fa[i]].push_back(i);w[i]=read();pi[i]=read();qi[i]=read();li[i]=read();
}dfs(1);solve(1,n);
for(int i=2;i<=n;++i) printf("%lld\n",dp[i]);
return 0;
}