DP方程显然:
fi=min(fj+(disi−disj)∗pi+qi)
f
i
=
m
i
n
(
f
j
+
(
d
i
s
i
−
d
i
s
j
)
∗
p
i
+
q
i
)
,dis是根到每个点的距离。
假设j的深度比k大且j这个决策比k更优,那么就有:
记这个斜率式为 slop(j,k) s l o p ( j , k ) ,如果存在i的深度大于j,j的深度大于k且 slop(i,j)<slop(j,k) s l o p ( i , j ) < s l o p ( j , k ) ,那么j一定不是最优决策。(因为如果 pi>slop(j,k) p i > s l o p ( j , k ) ,则i比较优,否则k比较优),所以我们要维护一个上凸壳。
考虑用点分治来实现树上斜率优化,假设当前在处理一个以now为根的子树。
1.找到重心x。
2.递归处理包含now的那个连通块带上x
3.将子树x中,除x以外的点,按照其一趟车可以到达的最小深度,从大到小排序。
4.依次处理这些点,每次把新的可以一趟车到达的点加入凸壳中,单调栈维护一下。然后二分答案寻找当前这个点的最优决策。
5.递归处理x的子树。
复杂度是 O(nlog2n) O ( n l o g 2 n ) 的。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL read() {
LL q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+(LL)(ch-'0'),ch=getchar();
return q;
}
#define RI register int
typedef double db;
const int N=200005;
int tot,n,t,rt,mx,js;
int h[N],ne[N],to[N],fa[N],sz[N],vis[N],P[N];
LL w[N],p[N],q[N],l[N],dis[N],f[N];
int st[N],top;db sl[N];
db slope(int x,int y) {return (db)(f[y]-f[x])/(db)(dis[y]-dis[x]);}
void ins(int x) {
while(top>=2&&sl[top-1]<=slope(st[top],x)) --top;
st[++top]=x,sl[top]=-1e18,sl[top-1]=slope(st[top-1],st[top]);
}
int query(db num) {
int l=1,r=top,mid,re;
while(l<=r) {
mid=(l+r)>>1;
if(sl[mid]<=num) re=mid,r=mid-1;
else l=mid+1;
}
return st[re];
}
void getrt(int x,int SZ) {
sz[x]=1;int bl=0;
for(RI i=h[x];i;i=ne[i])
if(!vis[to[i]])
getrt(to[i],SZ),sz[x]+=sz[to[i]],bl=max(bl,sz[to[i]]);
bl=max(bl,SZ-sz[x]);
if(bl<=mx) rt=x,mx=bl;
}
void dfs(int x) {
P[++js]=x;
for(RI i=h[x];i;i=ne[i]) if(!vis[to[i]]) dfs(to[i]);
}
bool cmp(int x,int y) {return dis[x]-l[x]>dis[y]-l[y];}
void work(int now,int SZ) {
if(SZ==1) return;
mx=1e9,getrt(now,SZ);int x=rt,kmx=mx;
for(RI i=h[x];i;i=ne[i]) vis[to[i]]=1,SZ-=sz[to[i]];
work(now,SZ);
js=0;for(RI i=h[x];i;i=ne[i]) dfs(to[i]);
sort(P+1,P+1+js,cmp);
int j=x;top=0;
for(RI i=1;i<=js;++i) {
int y=P[i];
while(j!=fa[now]&&dis[j]>=dis[y]-l[y]) ins(j),j=fa[j];
if(top) {
int k=query(p[y]);
f[y]=min(f[y],f[k]+(dis[y]-dis[k])*p[y]+q[y]);
}
}
for(RI i=h[x];i;i=ne[i]) work(to[i],sz[to[i]]);
}
void add(int x,int y,int z) {to[++tot]=y,ne[tot]=h[x],h[x]=tot,w[tot]=z;}
void getdis(int x)
{for(RI i=h[x];i;i=ne[i]) dis[to[i]]=dis[x]+w[i],getdis(to[i]);}
int main()
{
int z;n=read(),t=read();
for(RI i=2;i<=n;++i) {
fa[i]=read(),z=read(),add(fa[i],i,z);
p[i]=read(),q[i]=read(),l[i]=read(),f[i]=LLONG_MAX;
}
getdis(1);work(1,n);
for(RI i=2;i<=n;++i) printf("%lld\n",f[i]);
return 0;
}