这题好神啊..好神啊...好神啊...
首先列出N2的DP方程较易.
从DP方程很容易看出来是斜率优化.
如何进一步优化?
考虑对当前点以上的链建立一个下凸包.
维护凸包就可以,但不是很好写.
观察到方程可以必然由它的祖先节点转移.很像Cash那道题.
尝试CDQ分治,每次先递归处理根所在的子树.
然后用根所在的子树,对当前点更新答案,对其他点进行根据dis-lim排序,维护栈即可.
考虑到复杂度,我们需要对树进行点分治.
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<string>
#include<iomanip>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define FILE "dealing"
#define up(i,j,n) for(int i=j;i<=n;++i)
#define db double
#define uint unsigned ll
#define eps 1e-12
#define pii pair<ll,ll>
ll read(){
ll x=0,f=1,ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f*x;
}
const ll maxn=200500,limit=1e6,mod=(ll)(7+1e9+0.1);
const ll inf=(ll)(1e18);
template<class T>bool cmax(T& a,T b){return a<b?a=b,true:false;}
template<class T>bool cmin(T& a,T b){return a>b?a=b,true:false;}
template<class T>T min(T& a,T& b){return a<b?a:b;}
template<class T>T max(T& a,T& b){return a>b?a:b;}
int n,m;
ll fa[maxn],p[maxn],q[maxn],lim[maxn],dis[maxn],dui[maxn],f[maxn];
struct node{
int y,next,v;
}e[maxn];
int len,linkk[maxn];
void insert(int x,int y,ll v){
e[++len].y=y;
e[len].v=v;
e[len].next=linkk[x];
linkk[x]=len;
}
int root=0,siz[maxn],vis[maxn],Max[maxn],cnt;
struct Node{
ll val,id;
}a[maxn];
void dfs1(ll x){
siz[x]=1;
for(ll i=linkk[x];i;i=e[i].next){
dis[e[i].y]=dis[x]+e[i].v;
dfs1(e[i].y);
siz[x]+=siz[e[i].y];
}
}
void find_root(ll x,int S,ll& rt){
Max[x]=0,siz[x]=1;
for(ll i=linkk[x];i;i=e[i].next){
if(vis[e[i].y])continue;
find_root(e[i].y,S,rt);
siz[x]+=siz[e[i].y];
cmax(Max[x],siz[e[i].y]);
}
cmax(Max[x],S-siz[x]);
if(Max[x]<Max[rt]&&siz[x]>1)rt=x;
}
void dfs2(ll x){
a[++cnt].val=dis[x]-lim[x];
a[cnt].id=x;
for(ll i=linkk[x];i;i=e[i].next)
if(!vis[e[i].y])dfs2(e[i].y);
}
bool cmp(Node a,Node b){
return a.val>b.val;
}
ll upd(ll x,ll y){return f[y]+(dis[x]-dis[y])*p[x]+q[x];}
db K(ll x,ll y){return (1.0*f[x]-f[y])/(dis[x]-dis[y]);}
void solve(ll x,int S){
if(S==1)return;ll rt=0,now=0;
find_root(x,S,rt);
for(ll i=linkk[rt];i;i=e[i].next)
vis[e[i].y]=1;
solve(x,S-siz[rt]+1);
cnt=0;
for(ll i=linkk[rt];i;i=e[i].next)dfs2(e[i].y);
sort(a+1,a+cnt+1,cmp);
now=rt;
int tail=0,l,r,mid,pos;
for(ll i=1;i<=cnt;i++){
while(now!=fa[x]&&dis[a[i].id]-lim[a[i].id]<=dis[now]){
while(tail>1&&K(dui[tail],now)>=K(dui[tail],dui[tail-1]))tail--;
dui[++tail]=now;now=fa[now];
}
if(tail>0){
l=1,r=tail,pos=1;
while(l<=r){
mid=(l+r)>>1;if(mid==tail){pos=tail;break;}
if(K(dui[mid],dui[mid+1])>=p[a[i].id])l=mid+1,pos=mid+1;
else r=mid-1;
}
cmin(f[a[i].id],upd(a[i].id,dui[pos]));
}
}
for(ll i=linkk[rt];i;i=e[i].next)solve(e[i].y,siz[e[i].y]);
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read();ll d=read();
up(i,2,n){
ll y=read(),v=read();
fa[i]=y;
insert(y,i,v);
p[i]=read(),q[i]=read();
lim[i]=read();
}
dfs1(1);Max[0]=n+1;
up(i,2,n)f[i]=inf;
solve(1,siz[1]);
up(i,2,n)printf("%lld\n",f[i]);
return 0;
}