解析
第一道完全自己做出来的黑题awa
(如果不算那道感觉完全是恶评的石油的话)
然而连写带调整了3.5h…
容易想到链的做法
设ancxanc_xancx表示x的祖先,disxdis_xdisx表示x到1的距离
则有:
dpv=mindisv−lv<=disu,u∈ancv(dpu+pv×(disv−disu)+qvdp_v=\min_{dis_v-l_v<=dis_u,u\in anc_v}(dp_u+p_v\times (dis_v-dis_u)+q_vdpv=disv−lv<=disu,u∈ancvmin(dpu+pv×(disv−disu)+qv
这个就可以斜优了
然后考虑如何上树
树比较恶心的地方就是我们的队列会随着dfs分支的改变而变化
难以解决
换个思路
考虑点分治
对与当前的重心 rt,
先把rt到1的那个联通块递归solve掉
然后再把联通块内rt的返祖链取下来
再dfs找到所有联通块内的其他点
按照能到达的最大高度sort一下
然后做个指针动态维护这个凸包,二分更新就行了
代码
#include<bits/stdc++.h>
using namespace std;
#define ll __int128
#define inf (n+1)
//#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
const int M=2e5+10500;
const double eps=1e-5;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
void write(ll x){if(x<0){putchar('-');x=-x;}if(x>9) write(x/10);putchar('0'+x%10);return;
}int n,m;
int debug(0);struct node{int to,nxt;ll w;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y,ll w){p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return;
}ll dp[N],P[N],Q[N],dis[N],l[N];
int fa[N],siz[N],mx[N],S,rt;
int que[N],num1;
int v[N],num2;
bool vis[N];void find(int x,int f){siz[x]=1;mx[x]=0;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;find(to,x);siz[x]+=siz[to];mx[x]=max(mx[x],siz[to]);} mx[x]=max(mx[x],S-siz[x]);if(!rt||mx[rt]>mx[x]) rt=x;return;
}void dfs(int x,int top){que[++num1]=x;//if(debug) printf("dfs:x=%d f=%d tot=%d\n",x,f,tot);if(x==top) return;dfs(fa[x],top);return;
}#define X(o) dis[o]
#define Y(o) dp[o]
int q[N],le,ri;inline void upd(int x){int st=le,ed=ri;while(st<ed){int mid=(st+ed)>>1,o=q[mid];if(dis[x]-dis[o]>l[x]||(mid<ri&&P[x]*(X(q[mid+1])-X(q[mid]))>=(Y(q[mid+1])-Y(q[mid])))) st=mid+1;else ed=mid;//if(debug) printf(" mid=%d o=%d d=%lld %d||(%d&&%d) (%d %d)\n",mid,o,(long long)(dis[x]-dis[o]),dis[x]-dis[o]>l[x],mid<tot,P[x]*(X(q[num+1])-X(q[num]))>=(Y(q[num+1])-Y(q[num])),st,ed);}if(st==ed&&dis[x]-dis[q[st]]<=l[x]){int u=q[st];dp[x]=min(dp[x],P[x]*(dis[x]-dis[u])+dp[u]+Q[x]);if(debug) printf(" update: x=%d u=%d dp=%lld\n",x,u,(long long)dp[x]);}return;
}inline void add(int x){if(debug) printf(" add:x=%d (%lld %lld)\n",x,(long long)X(x),(long long)Y(x));while(le<ri&&(Y(q[le])-Y(x))*(X(q[le+1])-X(q[le]))>=(Y(q[le+1])-Y(q[le]))*(X(q[le])-X(x))) ++le;q[--le]=x;if(debug) for(int i=le;i<=ri;i++) printf("[%d]:(%lld %lld) ",q[i],(long long)X(q[i]),(long long)Y(q[i]));if(debug) putchar('\n');return;
}void get(int x,int f){v[++num2]=x;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;get(to,x);}return;
}
int findtop(int x){return fa[x]&&!vis[fa[x]]?findtop(fa[x]):x;
}
int calc(int x,int f){int res(1);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;res+=calc(to,x);}return res;
}
bool cmp(int x,int y){return dis[x]-l[x]>dis[y]-l[y];
}
void solve(int x){S=calc(x,0);rt=0;find(x,0);x=rt;vis[x]=1;int top=findtop(x);if(debug) printf("\nsolve: %d (S=%d top=%d)\n",x,S,top);if(fa[x]&&!vis[fa[x]]){solve(fa[x]);}if(debug) printf("\nbeginwork:%d\n",x);num1=0;num2=0;dfs(x,top);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]||to==fa[x]) continue;get(to,x);}sort(v+1,v+1+num2,cmp);if(debug){printf("que:");for(int i=1;i<=num1;i++) printf("%d ",que[i]);putchar('\n');printf("v:");for(int i=1;i<=num2;i++) printf("%d ",v[i]);putchar('\n');}for(int i=1;i<=num1;i++){int u=que[i];if(dis[x]-dis[u]>l[x]) break;dp[x]=min(dp[x],dp[u]+P[x]*(dis[x]-dis[u])+Q[x]);}int pl=1;ri=n;le=n+1;for(int i=1;i<=num2;i++){while(pl<=num1&&dis[v[i]]-l[v[i]]<=dis[que[pl]]){add(que[pl]);++pl;}upd(v[i]);}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]) continue;solve(to);}return;
}void init(int x,int f){for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dis[to]=dis[x]+p[i].w;init(to,x);}return;
}
int main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();int zhennanrencongbuxiebufenfen=read();//assert(zhennanrencongbuxiebufenfen<=3);for(int i=2;i<=n;i++) dp[i]=2e18;dp[1]=0;for(int i=2;i<=n;i++){fa[i]=read();ll w=read();P[i]=read();Q[i]=read();l[i]=read();addline(fa[i],i,w);addline(i,fa[i],w);}init(1,0);siz[1]=n;solve(1);for(int i=2;i<=n;i++) write(dp[i]),putchar('\n');return 0;
}
/**/