BZOJ3672 [Noi2014]购票
dp方程很好列:f[i]=min(f[j]+(d[i]-d[j])*p[i]+q[i]),j是i的祖先且d[i]-l[i]<=d[j].
考虑序列上的做法,这东西显然可以斜率优化,如果j<k且j比k优,则(f[j]-f[k])/(d[j]-d[k])>=p[i].
但是方程对j的范围有一个限制,所以我们可以考虑分治。
假设现在正在处理l~mid对mid+1~r的影响。
我们把mid+1~r按d[i]-l[i]从大到小排序,用l~mid建一个凸包,每次相当于从凸包头插入点,然后询问一个斜率的最优值,二分一下就行了。
现在这个东西到了树上,我们考虑树的点分治。
按重心分治,先递归有根的那边,之后把重心子树内的点取出,用根到重心这段的f值去更新,方法同上。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N=200005,M=400005; int n,e,si,mx,rt,tp,Tp,fa[N],sz[N],p[N],hd[N],nx[M],to[M],v[N],st[N],St[N]; ll y,q[N],l[N],w[M],d[N],f[N]; void ad(int x,int y,ll z) {to[++e]=y,w[e]=z,nx[e]=hd[x],hd[x]=e;} bool cmp(int x,int y) {return d[x]-l[x]>d[y]-l[y];} void dfs(int x,int fa) { sz[x]=1; int Mx=0; for(int i=hd[x];i;i=nx[i]) if(to[i]!=fa&&!v[to[i]]) dfs(to[i],x),sz[x]+=sz[to[i]],Mx=max(Mx,sz[to[i]]); Mx=max(Mx,si-sz[x]); if(Mx<mx) mx=Mx,rt=x; } void dfs2(int x,int fa) {sz[x]=1; for(int i=hd[x];i;i=nx[i]) if(to[i]!=fa&&!v[to[i]]) dfs2(to[i],x),sz[x]+=sz[to[i]];} void dfs3(int x,int fa) {st[++tp]=x; for(int i=hd[x];i;i=nx[i]) if(to[i]!=fa&&!v[to[i]]) dfs3(to[i],x);} double xl(int j,int k) {return (double)(f[j]-f[k])/(d[j]-d[k]);} void mrg(int y,int x) { dfs2(x,0),v[x]=1; if(x!=1&&!v[fa[x]]) mx=si=sz[fa[x]],dfs(fa[x],0),mrg(y,rt); tp=Tp=0,dfs3(x,fa[x]),sort(st+1,st+1+tp,cmp); for(int i=1,u=fa[x];i<=tp;i++) { while(u!=fa[y]&&d[st[i]]-l[st[i]]<=d[u]) { while(Tp>1&&xl(St[Tp-1],St[Tp])<=xl(St[Tp],u)) Tp--; St[++Tp]=u,u=fa[u]; } if(!Tp) continue; int l=1,r=Tp; while(l<r) { int m=(l+r)>>1; if(xl(St[m],St[m+1])<p[st[i]]) r=m; else l=m+1; } f[st[i]]=min(f[st[i]],f[St[l]]+(d[st[i]]-d[St[l]])*p[st[i]]+q[st[i]]); } for(int i=1;i<=tp;i++) if(st[i]!=x&&d[st[i]]-l[st[i]]<=d[x]) f[st[i]]=min(f[st[i]],f[x]+(d[st[i]]-d[x])*p[st[i]]+q[st[i]]); for(int i=hd[x];i;i=nx[i]) if(!v[to[i]]&&to[i]!=fa[x]) mx=si=sz[to[i]],dfs(to[i],0),mrg(to[i],rt); } int main() { scanf("%d%*d",&n),memset(f,0x3f,sizeof f),f[1]=0; for(int i=2;i<=n;i++) scanf("%d%lld%d%lld%lld",&fa[i],&y,&p[i],&q[i],&l[i]),ad(fa[i],i,y),ad(i,fa[i],y),d[i]=d[fa[i]]+y; si=mx=n,dfs(1,0),mrg(1,rt); for(int i=2;i<=n;i++) printf("%lld\n",f[i]); return 0; }