题目放个传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3672
很容易推出暴力dp:f[i]=f[j]+p[i]*(dep[i]-dep[j])+q[i]。
我们可以设k=dep[j],b=f[j],x=p[i],如果是链斜率优化即可。不是链的话,每次把每个节点到根的路径取出来处理即可。
正解:点分治+cdq分治。(本蒟蒻太懒(弱)了不想(会)写。)
本蒟蒻写的暴力:树链剖分,对于每个线段树结点建立一个凸包,每次查询操作在凸包上二分斜率即可。复杂度O(n*log(n)^3),看起来很吓人对吧,然而仔细一看不难发现常数极小,可以轻松水过。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<algorithm>
#define ll long long
#define inf 99999999999999999ll
#define N 200010
using namespace std;
int n,fa[N],p[N];
int size[N],top[N],next[N],flag[N];
int st[N],end[N],pos[N],num[N],pl[N],tot,rt[N];
int la[N],ff[N],Q[N],s[N*18],tmp,cnt;
ll f[N],len[N],q[N],dis[N];
struct node{int a,b;ll c;}map[N];
struct point{
int lc,rc,fa,l,sum;
double cal(int x,int y)
{
return double(f[x]-f[y])/(dis[x]-dis[y]);
}
void insert(int x)
{
if(sum<2){s[l+sum]=x,sum++;return;}
while(sum-1&&cal(s[l+sum-2],s[l+sum-1])>=cal(s[l+sum-2],x))sum--;
s[l+sum]=x;sum++;
}
ll qry(int x)
{
int lx=l,rx=l+sum-1;
while(rx-lx>1)
{
int mid=lx+rx>>1;
if(cal(s[mid],s[mid+1])>p[x])rx=mid;
else lx=mid+1;
}
return min(f[s[lx]]-p[x]*dis[s[lx]],f[s[rx]]-p[x]*dis[s[rx]]);
}
}t[N*4];
class seg_tree
{
vector<pair<ll,int> >tp;
ll qry(int x,int l,int r,int ql,int qr,int k)
{
if(ql<=l&&r<=qr){return t[x].qry(k);}
int lc=t[x].lc,rc=t[x].rc,mid=l+r>>1;
ll res=inf;
if(ql<=mid)res=min(res,qry(lc,l,mid,ql,qr,k));
if(qr>mid)res=min(res,qry(rc,mid+1,r,ql,qr,k));
return res;
}
public:
void build(int x,int l,int r)
{
t[x].l=tmp+1;t[x].sum=0;tmp+=r-l+1;
if(l==r){pl[num[l]]=x;return;}
int mid=l+r>>1;
build(t[x].lc=++cnt,l,mid);
build(t[x].rc=++cnt,mid+1,r);
t[t[x].lc].fa=x;t[t[x].rc].fa=x;
}
ll query(int x,int ql,int qr,int k)
{
if(tp.empty()||dis[k]-len[k]>dis[num[qr]])return inf;
if(dis[k]-len[k]<=dis[num[ql]])return qry(rt[x],st[x],end[x],ql,qr,k);
int pp=lower_bound(tp.begin()+ql-1,tp.begin()+qr-1,make_pair(dis[k]-len[k],0))->second;
return qry(rt[x],st[x],end[x],max(pp,ql),qr,k);
}
void insert(int x)
{
for(int p=pl[x];p;p=t[p].fa)t[p].insert(x);
tp.push_back(make_pair(dis[x],pos[x]));
}
}T[N];
void bfs()
{
int l=1,r=2;Q[1]=1;
while(l<r)
{
int x=Q[l];size[x]=1;l++;
for(int a=la[x];a;a=ff[a])
Q[r]=map[a].b,dis[Q[r]]=dis[x]+map[a].c,r++;
}
for(int i=r-1;i;i--)
{
int x=Q[i];size[fa[x]]+=size[x];
if(size[next[fa[x]]]<size[x])next[fa[x]]=x;
}
for(int i=1;i<r;i++)
{
int x=Q[i];
if(flag[x])continue;st[x]=tot+1;
for(int j=x;j;j=next[j])
pos[j]=++tot,num[tot]=j,top[j]=x,flag[j]=1;
end[x]=tot;
T[x].build(rt[x]=++cnt,st[x],end[x]);
}
}
int main()
{
int a;ll c;
scanf("%d%d",&n,&a);
for(int i=2;i<=n;i++)
{
scanf("%d%lld%d%lld%lld",&a,&c,&p[i],&q[i],&len[i]);
map[i]=(node){a,i,c};ff[i]=la[a];la[a]=i;fa[i]=a;
}
bfs();T[1].insert(1);
for(int i=2;i<=n;i++)
{
int v=Q[i],x,y;
f[v]=T[top[v]].query(top[v],st[top[v]],pos[v]-1,v);
x=fa[top[v]];y=top[x];
for(;x;x=fa[y],y=top[x])
f[v]=min(f[v],T[y].query(y,st[y],pos[x],v));
f[v]+=(ll)p[v]*dis[v]+q[v];T[top[v]].insert(v);
}
for(int i=2;i<=n;i++)printf("%lld\n",f[i]);
return 0;
}