警告 本篇文章作者大脑已成一团浆糊,为了保证文章的流畅性,请阅读者将脑子搅成纸浆后方可正常阅读
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]); }