http://acm.hdu.edu.cn/showproblem.php?pid=5956
转移方程:dp[i]=(dis[i]-dis[j])*(dis[i]-dis[j])+P+dp[j]
斜率优化,可持久化单调队列维护
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 100001 typedef long long LL; int P; int front[N],to[N<<1],nxt[N<<1],val[N<<1],tot; int dis[N]; int head,tail,q[N]; LL dp[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); } } void add(int u,int v,int w) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w; } inline double X(int i,int j) { return dis[j]-dis[i]; } inline double Y(int i,int j) { return 1LL*dis[j]*dis[j]+dp[j]-1LL*dis[i]*dis[i]-dp[i]; } void dfs(int x,int y) { int now_h=head,now_t=tail; int l=head,r=tail-2,mid,tmp=-1; while(l<=r) { mid=l+r>>1; if(Y(q[mid],q[mid+1])>=2*dis[x]*X(q[mid],q[mid+1])) tmp=mid,r=mid-1; else l=mid+1; } if(tmp!=-1) head=tmp; else head=tail-1; int j=q[head]; dp[x]=1LL*(dis[x]-dis[j])*(dis[x]-dis[j])+P+dp[j]; l=head,r=tail-2,tmp=-1; while(l<=r) { mid=l+r>>1; if(Y(q[mid],q[mid+1])*X(q[mid+1],x)<=Y(q[mid+1],x)*X(q[mid],q[mid+1])) tmp=mid,l=mid+1; else r=mid-1; } if(tmp!=-1) tail=tmp+2; else tail=head+1; int rr=q[tail]; q[tail++]=x; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) { dis[to[i]]=dis[x]+val[i]; dfs(to[i],x); } head=now_h; q[tail-1]=rr; tail=now_t; } void clear() { tot=0; memset(front,0,sizeof(front)); } int main() { int T; read(T); int n,u,v,w; while(T--) { clear(); read(n); read(P); for(int i=1;i<n;++i) { read(u); read(v); read(w); add(u,v,w); } dp[1]=-P; for(int i=front[1];i;i=nxt[i]) { head=0; tail=1; q[0]=1; dis[to[i]]=val[i]; dfs(to[i],1); } LL ans=0; for(int i=2;i<=n;++i) ans=max(ans,dp[i]); cout<<ans<<‘\n‘; } }