题目描述
题解
考虑啥限制都没有的话,也就是在一个序列上且没有 l l l 的限制,那就是 d p dp dp 然后斜率优化
f i f_i fi 表示 i i i 的答案, f i = m i n ( f j + ( d i − d j ) p i + q i ) f_i=min(f_j+(d_i-d_j)p_i+q_i) fi=min(fj+(di−dj)pi+qi) ,其中 d i d_i di 表示 s s s 的前缀和,可以化成斜率优化的式子
由于斜率不递增所以在凸包上二分即可
考虑 l l l 的限制的话,那我们可以做类似 c d q cdq cdq 的东西,也就是考虑 [ l , m i d ] [l,mid] [l,mid] 对 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的影响,那可以对右区间以最前能取到的点从大到小排序,然后双指针加入凸包即可
考虑在一棵树上的话,那我们考虑点分治,即对于树 u u u 求出了重心 r t rt rt ,考虑 ( u , r t ) (u,rt) (u,rt) 路径上的点对 r t rt rt 子树的影响,那我们可以先除去 r t rt rt 子树内的点(除了 r t rt rt ),然后递归求出剩下点的 d p dp dp 值,然后我们可以像刚刚的操作即把 r t rt rt 子树内除了 r t rt rt 的点按照最高能取到的点按深度从大到小排序,然后双指针加入凸包即可
效率: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
代码
#include <bits/stdc++.h>
#define LL long long
#define db long double
using namespace std;
const int N=2e5+5;
int n,fa[N],o,rt,sz[N],son[N],a[N],hd[N],V[N],nx[N],t,S[N],tp;
LL d[N],s[N],p[N],q[N],g[N],f[N];bool vis[N];
bool cmp(int A,int B){
return d[A]-g[A]>d[B]-g[B];
}
void add(int u,int v){
nx[++t]=hd[u];V[hd[u]=t]=v;
}
db K(int x,int y){
return ((db)f[y]-f[x])/((db)d[y]-d[x]);
}
void Dis(int x){
for (int i=hd[x];i;i=nx[i])
d[V[i]]=d[x]+s[V[i]],Dis(V[i]);
}
void Sz(int x){
sz[x]=1;
for (int i=hd[x],v;i;i=nx[i])
if (!vis[v=V[i]])
Sz(v),sz[x]+=sz[v];
}
void Rt(int x){
son[x]=o-sz[x];
for (int i=hd[x],v;i;i=nx[i])
if (!vis[v=V[i]])
Rt(v),son[x]=max(son[x],sz[v]);
if (son[x]<=son[rt]) rt=x;
}
void find(int x){
a[++t]=x;
for (int i=hd[x];i;i=nx[i])
if (!vis[V[i]]) find(V[i]);
}
void work(int x){
Sz(x);o=sz[x];rt=0;Rt(x);
if (o==1){vis[x]=1;return;}
for (int i=hd[rt];i;i=nx[i]) vis[V[i]]=1;
int u=rt;work(x);tp=t=0;
for (int i=hd[u];i;i=nx[i])
vis[V[i]]=0,find(V[i]);
sort(a+1,a+t+1,cmp);int X=x;x=u;
for (int i=1,v,l,r,j;i<=t;i++){
v=a[i];
while(d[u]>=d[X] && d[u]>=d[v]-g[v]){
while(tp>1 && K(S[tp-1],u)>=K(S[tp-1],S[tp])) tp--;
S[++tp]=u;u=fa[u];
}
if (!tp) continue;l=1;r=tp;
while(l<r){
j=(l+r+1)>>1;
if (K(S[j],S[j-1])>=p[v]) l=j;
else r=j-1;
}
f[v]=min(f[v],f[S[l]]+(d[v]-d[S[l]])*p[v]+q[v]);
}
vis[x]=1;
for (int i=hd[x];i;i=nx[i]) work(V[i]);
}
int main(){
cin>>n>>tp;son[0]=1e9;d[0]=-1;
for (int i=2;i<=n;i++)
scanf("%d%lld%lld%lld%lld",
&fa[i],&s[i],&p[i],&q[i],&g[i]),
f[i]=2e18,add(fa[i],i);
Dis(1);work(1);
for (int i=2;i<=n;i++)
printf("%lld\n",f[i]);
return 0;
}