斜率优化+点分治(CDQ?)
首先处理一个分治中心到这一块子树的最高点(子树的根)的链上的DP值
优先分治处理包含根的子树,然后再处理其他子树
#include<cstdio>
#include<algorithm>
using namespace std;
long long root,Num,N,st,Top,cnt,last[1000005],sz[1000005],F_[1000005],p[1000005],q[1000005],lim[1000005],Dep[1000005],Fa[1000005],vis[1000005];
long long F[1000005];
struct node1{
long long k,b;
}stack[1000005];
struct node2{
long long x,val;
}E[1000005];
struct node{
int to,next;
long long val;
}e[1000005];
void add(int a,int b,long long c){
e[++cnt].to=b;
e[cnt].next=last[a];
e[cnt].val=c;
last[a]=cnt;
}
void dfs(int x,int fa,long long dep){
sz[x]=1;
Dep[x]=dep;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (V==fa) continue;
dfs(V,x,dep+e[i].val);
sz[x]+=sz[V];
}
}
void find_root(int x,int fa){
sz[x]=1,F_[x]=0;
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (vis[V] || V==fa) continue;
find_root(V,x);
sz[x]+=sz[V];
F_[x]=max(F_[x],sz[V]);
}
F_[x]=max(F_[x],N-sz[x]);
if (F_[x]<F_[root]) root=x;
}
void Pre(int x,int fa){
E[++Num]=(node2){x,Dep[x]-lim[x]};
for (int i=last[x]; i; i=e[i].next){
int V=e[i].to;
if (vis[V] || V==fa) continue;
Pre(V,x);
}
}
bool cmp(node2 a,node2 b){
return a.val>b.val;
}
double check(node1 a,node1 b){
return ((double)a.b-b.b)/(b.k-a.k);
}
void insert(int x){
node1 line=(node1){-Dep[x],F[x]};
while (Top>1 && check(line,stack[Top])>=check(stack[Top],stack[Top-1])) Top--;
stack[++Top]=line;
}
void Divide(int x,int S){
if (S<=1) return;
root=0,N=S;
find_root(x,0);
int Root=root;
for (int i=last[Fa[root]]; i; i=e[i].next){
int V=e[i].to;
if (vis[V]) continue;
if (V==Root) {
vis[Root]=1;
Divide(x,sz[x]-sz[Root]);
break;
}
}
for (int now=Fa[Root]; now!=Fa[x]; now=Fa[now])
if (Dep[now]>=Dep[Root]-lim[Root]) F[Root]=min(F[Root],F[now]+1ll*(Dep[Root]-Dep[now])*p[Root]+q[Root]);
Num=0;
for (int i=last[Root]; i; i=e[i].next){
int V=e[i].to;
if (vis[V] || V==Fa[Root]) continue;
Pre(V,Root);
}
sort(E+1,E+Num+1,cmp);
Top=0,st=Root;
for (int i=1; i<=Num; i++){
int X=E[i].x;
while (st!=Fa[x] && Dep[st]>=Dep[X]-lim[X]){
insert(st);
st=Fa[st];
}
if (Top){
int L=1,R=Top;
while (L<R){
int mid=(L+R)>>1;
double l,r;
if (mid==Top) l=-1ll<<60;
else l=check(stack[mid],stack[mid+1]);
if (mid==1) r=1ll<<60;
else r=check(stack[mid],stack[mid-1]);
if (p[X]>=l && p[X]<=r){
L=mid;
break;
}
else if (p[X]<l) L=mid+1;
else R=mid-1;
}
F[X]=min(F[X],1ll*Dep[X]*p[X]+q[X]+stack[L].b+stack[L].k*p[X]);
}
}
for (int i=last[Root]; i; i=e[i].next){
int V=e[i].to;
if (vis[V] || V==Fa[Root]) continue;
Divide(V,sz[V]);
}
}
int main(){
int n,t;
scanf("%d%d",&n,&t);
for (int i=2; i<=n; i++){
long long Len;
scanf("%lld%lld%lld%lld%lld",&Fa[i],&Len,&p[i],&q[i],&lim[i]);
add(Fa[i],i,Len);
add(i,Fa[i],Len);
}
dfs(1,0,0);
for (int i=2; i<=n; i++) F[i]=1ll<<60;
F_[0]=1e9;
Divide(1,n);
for (int i=2; i<=n; i++)
printf("%lld\n",F[i]);
return 0;
}
原文:https://www.cnblogs.com/silenty/p/9801021.html