题面
显然的一个建模是,每个叶子对应一个权值,代表比最晚的叶子早了多久,然后我们要做的就是给每条边赋上值,使得每个叶子到根的路径上的所有边权值和等于叶子的权值。
我们贪心的想一想,必然是离根越近的边赋值多的情况比较优(在保证同步的情况下),因为离根越近的边影响的叶子会更多。
而对于两个节点 u,v,我们必须要在lca(u,v)以下的边中赋值使得 u和v同步,因为再往上的边对u和v的影响就相同了。
于是根据以上两点,可以得到一个比较简单的dp。
f[x]表示以x为根的子树所有叶子同步的最小代价,转移很简单,留给大家想了w
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=500005;int hd[N],ne[N*2],to[N*2],val[N*2],num,n,S,mx[N];
ll f[N];inline void add(int x,int y,int z){to[++num]=y,ne[num]=hd[x],hd[x]=num,val[num]=z;
} inline int read(){int x=0; char ch=getchar();for(;!isdigit(ch);ch=getchar());for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';return x;
}void dfs(int x,int fa){for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa)dfs(to[i],x),mx[x]=max(mx[x],mx[to[i]]+val[i]);for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa)f[x]+=f[to[i]]+mx[x]-mx[to[i]]-val[i];
}int main(){n=read(),S=read();for(int i=1,u,v,w;i<n;i++) u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);dfs(S,0);printf("%lld\n",f[S]);return 0;
}