废话不多说,直接上方程。
dp[i]=min(dp[j]+(dis[i]−dis[j])×p[i]+q[i])
考虑
x
是
dp[x]−dis[x]∗p[i]<dp[y]−dis[y]∗p[i]
设
T(x,y)=dp[x]−dp[y]dis[x]−dis[y]<p[i]
即
T(x,y)<p[i],x∈son[y]
时,
x
比
如同我前面题解那样,可以证明两两决策斜率单调减,又因为不等式右边不单调,我们二分查找一个
T(x,y)>p[i],T(y,z)<p[i]
的
y
<script type="math/tex" id="MathJax-Element-1978">y</script>是最优决策。
由于这是一颗树,我们不可能直接像一维那么用单调队列搞,所以就树分治喽。
对于一颗子树,我们找出它的重心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]);
}