爲什麼我這麼慢!!!
這道題大概有兩種思路,樹分治和線段樹。
樹分治:使用類似cdq的方式,1:找重心,分裂,2:work(根所在的樹)3:用重心到根的點的答案更新重心的子樹,4:work(重心的子樹)。更新的時候維護一個下凸殼,在下凸殼上二分即可。(我寫了這個)
線段樹:同樣需要維護下凸殼,考慮在dfs時動態維護當前節點到根路徑上的區間下凸殼,這個用線段樹在每個節前維護一個支持回撤的單調棧,每次在棧上二分也是可以的。
時間複雜度O(nlog^2n)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define ll long long
#define ld long double
using namespace std;
ll n,fa[N],dep[N],sz[N],b[N],len[N],Mx[N],p[N],q[N];
ll first[N],to[N],nxt[N],l,fl[N],lenth[N];
ll a[N],m,dp[N],st[N];
ll read()
{
ll x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
bool cmp(ll x,ll y){return b[x]>b[y];}
void link(ll x,ll y,ll z)
{
to[++l]=y;lenth[l]=z;nxt[l]=first[x];first[x]=l;
}
void dfs(ll x)
{
b[x]=max(0LL,dep[x]-len[x]);
for (ll i=first[x];i;i=nxt[i])
{
dep[to[i]]=dep[x]+lenth[i];
dfs(to[i]);
}
}
void Get(ll x,ll y,ll &G)
{
sz[x]=1;Mx[x]=0;
for (ll i=first[x];i;i=nxt[i])
if (!fl[i])
{
Get(to[i],y,G);
sz[x]+=sz[to[i]];
Mx[x]=max(Mx[x],sz[to[i]]);
}
Mx[x]=max(Mx[x],y-sz[x]);
if (Mx[x]<=y/2) G=x;
}
void Dfs(ll x)
{
a[++m]=x;
for (ll i=first[x];i;i=nxt[i])
if (!fl[i])
Dfs(to[i]);
}
bool pd(ll x,ll y,ll z)
{
return (ld)(dp[z]-dp[x])/(dep[z]-dep[x])>(ld)(dp[z]-dp[y])/(dep[z]-dep[y]);
}
ll find(ll l,ll r,ll p)
{
ll mid,ans=l;l++;
while(l<=r)
{
mid=l+r>>1;
if ( (ld)(dp[st[mid-1]]-dp[st[mid]])/(dep[st[mid-1]]-dep[st[mid]])> p)
ans=mid,l=mid+1;
else r=mid-1;
}
return st[ans];
}
void work(ll x,ll y)
{
if (y==1) return;
ll G=0;
Get(x,y,G);
for (ll i=first[G];i;i=nxt[i])
fl[i]=1;
work(x,y-sz[G]+1);
m=0;
for (ll i=first[G];i;i=nxt[i])
Dfs(to[i]);
sort(a+1,a+m+1,cmp);
ll r=1,tp=0;
while(r<=m&&b[a[r]]>dep[G]) r++;
for (ll i=G;i!=fa[x];i=fa[i])
{
if (!(tp&&dp[i]>=dp[st[tp]]))
{
while(tp>=2&& pd(i,st[tp],st[tp-1]) ) tp--;
st[++tp]=i;
}
for (;r<=m&&(b[a[r]]>dep[fa[i]]||i==x);r++)
{
ll t=find(1,tp,p[a[r]]);
t=dp[t]+(dep[a[r]]-dep[t])*p[a[r]]+q[a[r]];
dp[a[r]]=min(dp[a[r]],t);
}
}
for (ll i=first[G];i;i=nxt[i])
work(to[i],sz[to[i]]);
}
int main()
{
n=read();read();dp[1]=0;
for (ll i=2,o;i<=n;i++)
{
fa[i]=read();o=read();p[i]=read();q[i]=read();len[i]=read();
link(fa[i],i,o);dp[i]=1e18;
}
dfs(1);work(1,n);
for (ll i=2;i<=n;i++)
printf("%lld\n",dp[i]);
}