bzoj 3672: [Noi2014]购票 树上cdq分治
2016-05-04 20:30
477 查看
显然易得dp方程:f[x]=min{f[y]+(d[x]-d[y])*px+qx},其中y是x的祖先且d[x]-d[y]<=lx。
然后就可以得到对于一定定点z(就是z在等式左边),两个点x,y(d[x]>d[y])且y更优的条件为:(f[x]-f[y])/(d[x]-d[y])>=pz,那么令不等式左边那个为S(x,y)即(x,y)的斜率。
考虑一条链的情况,显然可以离线后cdq分治。
树上的话,不妨称之为树上cdq分治(好吧承认是我自己yy的名字)。就找到重心G,然后维护G到root的f[]的一个凸壳,来更新G和G的子树。时间复杂度O(Nlog^2N)。
AC代码如下:
by lych
2016.5.4
然后就可以得到对于一定定点z(就是z在等式左边),两个点x,y(d[x]>d[y])且y更优的条件为:(f[x]-f[y])/(d[x]-d[y])>=pz,那么令不等式左边那个为S(x,y)即(x,y)的斜率。
考虑一条链的情况,显然可以离线后cdq分治。
树上的话,不妨称之为树上cdq分治(好吧承认是我自己yy的名字)。就找到重心G,然后维护G到root的f[]的一个凸壳,来更新G和G的子树。时间复杂度O(Nlog^2N)。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define N 200005 using namespace std; int n,tp,all,fst ,nxt ,fa ,sz ,q ,stk ; ll len ,f ,a ,b ,c ,d ; double slp ; bool ok ; ll read(){ ll x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } bool cmp(const int &x,const int &y){ return d[x]-c[x]>d[y]-c[y]; } int findct(int x){ int y,u=x,v; sz[x]=1; for (y=fst[x]; y; y=nxt[y]) if (ok[y]){ v=findct(y); sz[x]+=sz[y]; if ((sz[y]<<1)>all) u=v; } return u; } void dfs(int x){ int y; stk[++tp]=x; for (y=fst[x]; y; y=nxt[y]) if (ok[y]) dfs(y); } double getk(int x,int y){ return (double)(f[x]-f[y])/(d[x]-d[y]); } void calc(int x,int r){ int l=1,mid; while (l<r){ mid=(l+r)>>1; if (slp[mid]>=a[x]) l=mid+1; else r=mid; } f[x]=min(f[x],f[q[l]]+(d[x]-d[q[l]])*a[x]+b[x]); } void solve(int rt){ int x=findct(rt),y; ok[x]=0; if (x!=rt){ all=sz[rt]-sz[x]; solve(rt); tp=0; dfs(x); sort(stk+1,stk+tp+1,cmp); int i=1,now=fa[x],tail=1; q[1]=now; while (i<=tp && d[stk[i]]-d[q[1]]>c[stk[i]]) i++; for (; i<=tp; i++){ while (now!=rt && d[stk[i]]-d[fa[now]]<=c[stk[i]]){ now=fa[now]; while (tail>1 && getk(q[tail],now)>=slp[tail-1]) tail--; slp[tail]=getk(q[tail],now); q[++tail]=now; } calc(stk[i],tail); } } if (x==rt){ tp=0; dfs(x); } int i; for (i=1; i<=tp; i++) if (d[y=stk[i]]-d[x]<=c[stk[i]]) f[y]=min(f[y],f[x]+(d[y]-d[x])*a[y]+b[y]); for (y=fst[x]; y; y=nxt[y]) if (ok[y]){ all=sz[y]; solve(y); } } int main(){ scanf("%d",&n); int i; scanf("%d",&i); for (i=2; i<=n; i++){ scanf("%d",&fa[i]); nxt[i]=fst[fa[i]]; fst[fa[i]]=i; len[i]=read(); a[i]=read(); b[i]=read(); c[i]=read(); d[i]=d[fa[i]]+len[i]; } for (i=1; i<=n; i++) ok[i]=1; memset(f,0x3f,sizeof(f)); f[1]=0; all=n; solve(1); for (i=2; i<=n; i++) printf("%lld\n",f[i]); }
by lych
2016.5.4
相关文章推荐
- leetcode 171 Excel Sheet Column Number C++
- Java泛型
- The Donkey of Gui Zhou驴和老虎是否相遇问题(hdu4704)
- POJ 2195 Going Home(最小权匹配、KM算法)
- LeetCode-150.Evaluate Reverse Polish Notation
- jQuery选择器—表单对象属性过滤选择器
- OpenCV粒子滤波器用于物体跟踪
- Android Dev Intro - Android SurfaceTexture
- Android Dev Intro - SurfaceTexture,TextureView, SurfaceView and GLSurfaceView
- Android Dev Intro - Android Thread Intro
- 上机题-合并表记录
- 文章标题
- kill 与 kill -9(面试中问道的知识点)
- 跟王老师学集合(五)LinkedList集合类
- 【leetcode】141. Linked List Cycle
- 跟王老师学集合(四):使用foreach循环遍历元素
- Response.Redirect(),Server.Transfer(),Server.Execute()的区别
- 跟王老师学集合(三):使用Iterator接口遍历集合元素
- Redis和Memcache的区别
- Flash编码profile