这道题的难点就在于要删除点,但是我们把树进行树链剖分,这样操作就只剩下插入了!
说一些小细节吧:
-
树剖的线段树,只有当size满了才求一遍凸包,归并两个子树的凸包,这样常数小。
-
树剖的线段树,如果它的区间跨过了两条重链,就不用维护它了
注意(个人犯的错误):
-
维护的是右下凸包-Thanks to zky
-
在找到最浅的祖先时,还是老老实实倍增吧
-
叉积会爆long long,用double
下面的代码,注释掉的是三分,没有注释掉的是二分,都对。
#define N 200005 const LL inf=1ll<<62; int n; int v[N],nx[N],head[N],cnte; LL w[N]; il void adde(int uu,int vv,LL ww) { v[++cnte]=vv,w[cnte]=ww,nx[cnte]=head[uu],head[uu]=cnte; } LL P[N],Q[N],L[N],f[N]; int dfn[N],ot[N],dk,ys[N],sz[N],hsn[N],fa[N],top[N]; int b[N][18]; // max 2^17 LL path[N]; void dfs(int x,int f) { fa[x]=f,sz[x]=1; b[x][0]=f; for(ri i=1; i<=17&&b[x][i-1]; ++i) b[x][i]=b[b[x][i-1]][i-1]; for(ri i=head[x]; i; i=nx[i]) { path[v[i]]=path[x]+w[i]; dfs(v[i],x); sz[x]+=sz[v[i]]; if(sz[v[i]]>sz[hsn[x]]) hsn[x]=v[i]; } } const int rt=1; namespace seg { #define M N*4 #define ls (x<<1) #define rs (x<<1|1) #define gm int mid((l+r)/2) #define X(i) (path[i]) #define Y(i) (f[i]) vector<int>bao[M]; int st[N],tp; il bool cross(LL x1,LL y1,LL x2,LL y2) { return (double)y1*x2<(double)y2*x1; } void build(vector<int> &a,vector<int> &l,vector<int> &r) { tp=0; for(ri i=0; i<size(l); ++i) st[++tp]=l[i]; for(auto i:r) { while(tp>1&&cross(X(i)-X(st[tp-1]),Y(i)-Y(st[tp-1]),X(st[tp])-X(st[tp-1]),Y(st[tp])-Y(st[tp-1]))) --tp; st[++tp]=i; } a.resize(tp); for(ri i=1; i<=tp; ++i) a[i-1]=st[i]; } LL calc(int a,int b) { return f[a]+P[b]*(path[b]-path[a])+Q[b]; } LL calc(vector<int> &a,int p) { LL ans=inf; int l=0,r=size(a)-1; // while(r-l>3) // { // int lm=l+(r-l)/3,rm=r-(r-l)/3; // LL vl=calc(a[lm],p),vr=calc(a[rm],p); // if(vl<=vr) r=rm; // else l=lm; // } // for(ri i=l; i<=r; ++i) ans=min(calc(a[i],p),ans); LL k=P[p]; while(l<=r) { int mid=(l+r)/2; ans=min(calc(a[mid],p),ans); if(mid==size(a)-1) r=mid-1; else if(cross(X(a[mid+1])-X(a[mid]),Y(a[mid+1])-Y(a[mid]),1,k)) l=mid+1; else r=mid-1; } return ans; } bool bj[M]; void updbj(int x,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) bj[x]=1; if(l==r) return; gm; if(ql<=mid) updbj(ls,l,mid,ql,qr); if(qr>mid) updbj(rs,mid+1,r,ql,qr); } int sz[M]; void upd(int x,int l,int r,int p,int k) { ++sz[x]; if(l==r) { bao[x].pb(k); return; } gm; if(p<=mid) upd(ls,l,mid,p,k); else upd(rs,mid+1,r,p,k); if(bj[x]&&sz[x]==r-l+1) build(bao[x],bao[ls],bao[rs]); } LL query(int x,int l,int r,int ql,int qr,int k) { if(ql<=l&&r<=qr) { return calc(bao[x],k); } LL ans=inf; gm; if(ql<=mid) ans=query(ls,l,mid,ql,qr,k); if(qr>mid) ans=min(query(rs,mid+1,r,ql,qr,k),ans); return ans; } } void efs(int x,int tp) { ys[dfn[x]=++dk]=x; top[x]=tp; if(hsn[x]) { efs(hsn[x],tp); for(ri i=head[x]; i; i=nx[i]) if(v[i]!=hsn[x]) efs(v[i],v[i]); } else seg::updbj(rt,1,n,dfn[top[x]],dfn[x]); ot[x]=dk; } LL calc(int x) { int y=x,z=b[x][0]; for(ri i=17; i>=0; --i) if(b[y][i]&&path[x]-path[b[y][i]]<=L[x]) y=b[y][i]; LL ans=inf; while(top[z]!=top[y]) { ans=min(seg::query(rt,1,n,dfn[top[z]],dfn[z],x),ans); z=fa[top[z]]; } ans=min(seg::query(rt,1,n,dfn[y],dfn[z],x),ans); return ans; } void dfs(int x) { if(x!=1) f[x]=calc(x); seg::upd(rt,1,n,dfn[x],x); for(ri i=head[x]; i; i=nx[i]) dfs(v[i]); } void solve() { path[0]=-1; dfs(1,0); efs(1,1); dfs(1); } signed main() { #ifdef M207 freopen("in.in","r",stdin); // freopen("out.out","w",stdout); #endif LL wst; in(n),in(wst); for(ri i=2,a; i<=n; ++i) { in(a),in(wst), adde(a,i,wst); in(P[i]),in(Q[i]),in(L[i]); } solve(); for(ri i=2; i<=n; ++i) out(f[i]); return 0; }