警告 本篇文章作者大脑已成一团浆糊,为了保证文章的流畅性,请阅读者将脑子搅成纸浆后方可正常阅读
UPD:此题解已废,新题解戳这里
首先题目大意:
给定一棵以1为根的有根树,边有边权,每个点有三个参数:p,q,l
从该点可以走到它的祖宗节点处,前提是距离d不超过l且花销为pd+q
昨天时间不咋多,就没写。。。今天中午吃完饭开始写,结果一直写到五点半,一下午课都没去上,死定了0.0
这题如果不是数的话就是斜率优化 但是尼玛 这是棵树!
去网上搜了半天题解 写的基本都是树的分治 我还没写过0.0 就试着写了写
其实树的分治不难写 关键是那个该死的l。。。调了半天第三个点过不去,最后发现原来是这么挂的
问题就出在这种情况上,最优解不在凸包上,但是经过l的分割后l左侧的点无法选择,最优解就进入了凸包,这种情况没法维护。。。。
然后我回去重新看了下题解 尼玛 原来题解的意思是树分治+CDQ分治!我勒个去这代码复杂度明显不是我的单核小脑瓜能承受的0.0
最后我用暴力代替的CDQ,把l到得到的伪最优解之间的点一一枚举。。。然后惊奇地发现过了0.0 第四第五个点跑了2s多 还好没超时
最后贴代码0.0 写的有点惨 我慢 我慢!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 200200
using namespace std;
typedef long long ll;
struct abcd{
int to,next;
ll f;
int mark;
}table[M];
int head[M],tot;
void add(int x,int y,ll z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
int n,t,fa[M],siz[M],queue[M],mark[M],r,h,cnt;
ll p[M],q[M],l[M],f[M],dis[M];
typedef pair<ll,ll> point;
double getslope(point p1,point p2)
{
if(p1.first==p2.first)
return 2147483647*(p2.second>p1.second?1:-1);
return (double)( p2.second-p1.second )/( p2.first-p1.first );
}
point ps[M];
struct Convex_Hull{
point points[M];
int num[M],top;
double slope[M];
void insert(point p,int pos)
{
double s=0;
ll ff=p.second + ( dis[20] - p.first ) * ::p[20] + q[20];
if(top)
while(1)
{
s=getslope(points[top],p);
if(top==1)
break;
if( s<slope[top] )
top--;
else
break;
}
points[++top]=p;
slope[top]=s;
num[top]=pos;
}
int divide(ll d,double s)
{
int l,re;
l=lower_bound(points+1,points+top+1, make_pair(d,0ll) )-points;
if(l==top+1)
return -1;
re=lower_bound(slope+l+1,slope+top+1,s)-slope;
return re-1;
}
}hull;
void CDQ_Tree(int root,int size,int T)
{
int i,x,cog;
if(size==1)
return ;
r=h=0;queue[++r]=root;
while(r^h)
{
x=queue[++h];
siz[x]=1;
for(i=head[x];i;i=table[i].next)
if(!table[i].mark)
queue[++r]=table[i].to;
}
for(i=size;i;i--)
{
x=queue[i];
siz[fa[x]]+=siz[x];
if( (siz[x]<<1) > size )
mark[fa[x]]=cnt;
if( mark[x]!=cnt && (siz[x]<<1) >= size )
cog=x;
}
for(i=head[cog];i;i=table[i].next)
if(!table[i].mark)
table[i].mark=T;
CDQ_Tree(root,size-siz[cog]+1,++cnt);
for(i=head[cog];i;i=table[i].next)
if(table[i].mark==T)
table[i].mark=0;
r=0;
for(i=cog;i!=fa[root];i=fa[i])
queue[++r]=i;
hull.top=0;h=r;
hull.num[0]=r+1;
for(i=r;i;i--)
x=queue[i],ps[i]=make_pair(dis[x],f[x]),hull.insert( ps[i] , i );
for(i=head[cog];i;i=table[i].next)
queue[++r]=table[i].to;
while(r^h)
{
x=queue[++h];
int num=hull.divide( dis[x]-l[x] , (double)p[x] );
if(num>=0)
for(i=hull.num[num-1]-1;i>=hull.num[num];i--)
{
point p1=ps[i];
if(dis[x]-ps[i].first<=l[x])
f[x]=min( f[x] , p1.second + ( dis[x] - p1.first ) * p[x] + q[x] );
}
for(i=head[x];i;i=table[i].next)
if(!table[i].mark)
queue[++r]=table[i].to;
}
for(i=head[cog];i;i=table[i].next)
CDQ_Tree(table[i].to,siz[table[i].to],++cnt);
}
int main()
{
//freopen("ticket.in","r",stdin);
//freopen("ticket.out","w",stdout);
int i,x,y;
ll dist;
cin>>n>>t;
for(i=2;i<=n;i++)
{
scanf("%d%lld%lld%lld%lld",&fa[i],&dist,&p[i],&q[i],&l[i]);
add(fa[i],i,dist);
}
queue[++r]=1;
while(r^h)
{
x=queue[++h];
for(i=head[x];i;i=table[i].next)
dis[table[i].to]=dis[x]+table[i].f,queue[++r]=table[i].to;
}
memset(f,0x3f,sizeof f);f[1]=0;
CDQ_Tree(1,n,++cnt);
for(i=2;i<=n;i++)
printf("%lld\n",f[i]==4557430888798830399ll?0:f[i]);
}