http://www.lydsy.com/JudgeOnline/problem.php?id=3672
树上的CDQ分治。
和常规CDQ思路相同,一个点的可行决策点是从这个点往上连续一段,那么在分治过程中先递归重心往上的一块(包括重心这个点),再将其他点按可行深度排序,然后维护上面那些点的凸包来更新底下点的答案,最后分别递归底下的块即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<functional>
#include<algorithm>
#define gm 200001
using namespace std;
typedef long long ll;
int n,p[gm],fa[gm],t;
ll q[gm],l[gm],dep[gm];
bool ban[gm];
struct e
{
int t;
e *n;
ll c;
e(int t,e *n,const ll& c):t(t),n(n),c(c){}
}*f[gm];
void init(int x){for(e *i=f[x];i;i=i->n){dep[i->t]=dep[x]+i->c,init(i->t);}}
struct pnt
{
ll x,y;
pnt(const ll &x,const ll &y):x(x),y(y){}
ll b(int k){return y-k*x;}
};
double slope(const pnt &a,const pnt &b){return (double)(a.y-b.y)/(a.x-b.x);}
struct hull
{
vector<pnt> p;
vector<double> d;
int sz;
hull():p(),d(),sz(){}
~hull()=default;
void push_back(const pnt &a)
{
if(!sz)
{
p.push_back(a); d.push_back(1e100);
sz=1;
}
else
{
while(sz>1&&slope(p[sz-1],a)>d[sz-1])
{
--sz; p.pop_back(); d.pop_back();
}
p.push_back(a); d.push_back(slope(p[sz-1],a));
++sz;
}
}
ll find(const ll &k)
{
int pos=upper_bound(d.begin(),d.end(),(double)k,greater<double>())-d.begin()-1;
return p[pos].b(k);
}
bool empty() {return !sz;}
};
ll dp[gm];
int sz[gm];
int lim,g;
void dfs(int x)
{
bool is=1;
sz[x]=1;
for(e *i=f[x];i;i=i->n)
{
if(ban[i->t]) continue;
dfs(i->t);
if(sz[i->t]>lim>>1) is=0;
sz[x]+=sz[i->t];
}
if(lim-sz[x]>lim>>1) is=0;
if(is) g=x;
}
int r[gm],cnt;
void push(int x)
{
r[++cnt]=x;
for(e *i=f[x];i;i=i->n)
{
if(ban[i->t]) continue;
push(i->t);
}
}
struct cmp{bool operator() (int a,int b){return dep[a]-l[a]>dep[b]-l[b];}};
void solve(int rt,int tot)
{
lim=tot; dfs(rt); int x=g;
vector<int> lst;
for(e *i=f[x];i;i=i->n)
{
if(ban[i->t]) continue;
ban[i->t]=1; lst.push_back(i->t); tot-=sz[i->t];
}
if(rt!=x) solve(rt,tot);
ban[x]=1;cnt=0;
for(vector<int>::iterator it=lst.begin();it!=lst.end();++it){ban[*it]=0; push(*it);}
sort(r+1,r+cnt+1,cmp());
hull h;
for(int i=1;i<=cnt;++i)
{
int y=r[i];
while(x!=fa[rt]&&dep[x]>=dep[y]-l[y]) h.push_back(pnt(dep[x],dp[x])),x=fa[x];
if(!h.empty())
{
ll kre=h.find(p[y]);
dp[y]=min(dp[y],kre+p[y]*dep[y]+q[y]);
}
}
for(vector<int>::iterator it=lst.begin();it!=lst.end();++it){solve(*it,sz[*it]);}
}
int main()
{
scanf("%d%d",&n,&t);
memset(dp+1,0x7f,n<<3); dp[1]=0;
for(int i=2;i<=n;++i)
{
ll len;
scanf("%d%lld%d%lld%lld",fa+i,&len,p+i,q+i,l+i);
f[fa[i]]=new e(i,f[fa[i]],len);
}
init(1);
solve(1,n);
for(int i=2;i<=n;++i) printf("%lld\n",dp[i]);
return 0;
}