廢話不多說,直接上方程。
考慮
設
即
如同我前面題解那樣,可以證明兩兩決策斜率單調減,又因爲不等式右邊不單調,我們二分查找一個
由於這是一顆樹,我們不可能直接像一維那麼用單調隊列搞,所以就樹分治嘍。
對於一顆子樹,我們找出它的重心root,先遞歸根在的那一顆子樹,然後暴力算出root的dp值。
把root的孩子按照向上能夠到達的點的距離從大到小排序,這樣我們就可以保證只會一直往上往單調隊列裏面加點。
然後就沒了。搞了我一天,代碼能力弱啊。
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cassert>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<climits>
#define X first
#define Y second
#define DB double
#define MP make_pair
#define LL long long
#define int LL
#define pb push_back
#define sqr(_) ((_)*(_))
#define INF LONG_LONG_MAX/10
#define pii pair<int,int>
#define pdd pair<DB,DB>
#define ull unsigned LL
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int MAXN=5*1e5+10,MAXM=5*MAXN;
struct Civitatum{
LL fa,l,p,q,s;
}city[MAXN];
LL O;
template<typename T>void Read(T& x)
{
x=0;int flag=0,sgn=1;char c;
while(c=getchar())
{
if(c=='-')sgn=-1;
else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
else if(flag)break;
}
x*=sgn;
}
int n,sum,first[MAXN],next[MAXM],to[MAXM],w[MAXM];
int cnt=0,e,rt=0;
LL dp[MAXN],dis[MAXN];
bool can[MAXM];
int Marx[MAXN]={0x3f3f3f3f},st[MAXN],top=0,sz[MAXN];
DB k[MAXN];
vector<int> nodes;
void add(LL u,LL v,LL A)
{
next[e]=first[u];first[u]=e;to[e]=v;w[e]=A;can[e]=1;++e;
}
void DFS(int u)
{
for(int i=first[u];i!=-1;i=next[i])
{
int v=to[i];
if(v==city[u].fa)continue;
dis[v]=dis[u]+w[i];
DFS(v);
}
}
void Root(int u)
{
Marx[u]=0;sz[u]=1;
for(int i=first[u];i!=-1;i=next[i])
if(can[i])
{
int v=to[i];
Root(v);
sz[u]+=sz[v];
Marx[u]=max(Marx[u],sz[v]);
}
Marx[u]=max(Marx[u],sum-sz[u]);
if(Marx[u]<Marx[rt])rt=u;
}
DB slope(int x,int y)
{
return (DB)(dp[x]-dp[y])/(DB)(dis[x]-dis[y]);
}
void getNodes(int u)
{
for(int i=first[u];i!=-1;i=next[i])if(can[i])
{
int v=to[i];
if(v==city[u].fa)continue;
nodes.pb(v);
getNodes(v);
}
}
bool cmp(int x,int y)
{
return dis[x]-city[x].l>dis[y]-city[y].l;
}
void Insert(int x)
{
while((top>1)&&slope(st[top-1],st[top])<slope(st[top],x))
top--;
st[++top]=x;
if(st[top]==5&&st[top-1]==4)
st[top]=5;
if(top>1)k[top]=slope(st[top-1],st[top]);
}
LL update(int i,int j)
{
return dp[j]+(dis[i]-dis[j])*city[i].p+city[i].q;
}
int _find(int l,int r,DB p)
{
if(top==1)return 1;
if(k[l]<=p)return 1;
if(k[r-1]>=p)return r-1;
r--;
int mid,R=r;
while(l<=r)
{
mid=(l+r)>>1;
if(l==r)
{
if(k[mid]>p)
return mid;
else
return mid-1;
}
if(k[mid]>p&&(mid==R||k[mid+1]<=p))
return mid;
else if(k[mid+1]>p)
l=mid;
else
r=mid;
}
}
void work(int u,int id)
{
//DEBUG("%d %d\n",u,cnt);
if(sum<=1)return;
can[id]=top=rt=0;
Root(u);
int root=rt;
for(int i=first[city[root].fa];i!=-1;i=next[i])
{
int v=to[i];
if(v==root)
{
sum=sz[u]-sz[root];
work(u,i);
break;
}
}
LL _dis=0,res=INF;
int now=root;
top=0;
while(now!=u)
{
_dis+=city[now].s;
if(_dis>city[root].l)break;
now=city[now].fa;
res=min((LL)res,dp[now]-dis[now]*city[root].p);
}
dp[root]=min(dp[root],res+dis[root]*city[root].p+city[root].q);
nodes.clear();
getNodes(root);
if(!nodes.size())return;
sort(nodes.begin(),nodes.end(),cmp);
now=root,_dis=dis[nodes[0]]-dis[root];
while(now!=city[u].fa)
{
if(_dis>city[nodes[0]].l)break;
Insert(now);
_dis+=city[now].s;
now=city[now].fa;
}
int j;
if(top)
{
j=_find(2,top+1,city[nodes[0]].p);
if(j>top)j=1;
dp[nodes[0]]=min(dp[nodes[0]],update(nodes[0],st[j]));
}
for(int i=1;i<nodes.size();i++)
{
int pre=nodes[i];
while(dis[pre]-city[pre].l<=dis[now]&&now&&now!=city[u].fa)
Insert(now),now=city[now].fa;
if(!top)continue;
j=_find(2,top+1,(DB)city[pre].p);
if(j>top)j=1;
dp[pre]=min(dp[pre],update(pre,st[j]));
}
for(int i=first[root];i!=-1;i=next[i])
{
O++;
int v=to[i];
if(can[i])
sum=sz[v],work(v,i);
}
}
main()
{
#ifndef ONLINE_JUDGE
freopen("tick.in","r",stdin);
freopen("tick.out","w",stdout);
#endif
int t;
Read(n);Read(t);
memset(first,-1,sizeof(first));
for(int i=0;i<=n;i++)
dp[i]=INF;
for(int i=2;i<=n;i++)
{
Read(city[i].fa);Read(city[i].s);
Read(city[i].p);Read(city[i].q);Read(city[i].l);
add(city[i].fa,i,city[i].s);
}
sum=n;
dis[1]=0;
dp[1]=0;
DFS(1);
work(1,2*n+1);
for(int i=2;i<=n;i++)
printf("%lld\n",dp[i]);
}