这道题还是能比较容易的看出来它的树形结构的,时间即为边的长度,而且很显然的是,如果以 x x 为根的子树已经时态同步,那么以的儿子为根的子树肯定也已经时态同步,也就是说我们可以从 x x 的儿子的状态推到的状态,所以我们考虑树形DP。设 f[i] f [ i ] 表示在以 i i 为根的子树中达成时态同步需要最少用几次道具。
那么对于一个已经全部计算完毕的节点 x x ,如何计算呢?要想让以 x x 为根的子树时态同步,需要将所有的叶节点到的距离修改为这些距离里的最大值,也就是使用道具。所以我们需要记录这棵子树中叶节点到根的距离的最大值,并对其他子树进行修改(其实这一步不用真的写),同时更新 f[x] f [ x ] 。设以 i i 为根的子树里,所有叶节点中到根的最大距离是, f[i]=∑t[i]−(t[j]+len[i,j])+f[j] f [ i ] = ∑ t [ i ] − ( t [ j ] + l e n [ i , j ] ) + f [ j ] , j j 为的儿子。
最后别忘了开 longlong l o n g l o n g 。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=500000;
int n,rt,top,pre[(N<<1)+10],to[(N<<1)+10],len[(N<<1)+10],h[N+10];
long long f[N+10],t[N+10];
void ins(int u,int v,int w)
{
pre[++top]=h[u];h[u]=top;to[top]=v;len[top]=w;
}
void dfs(int x,int fa)
{
for(int i=h[x];i;i=pre[i])
{
int v=to[i];
if(v==fa)continue;
dfs(v,x);
t[x]=max(t[x],t[v]+len[i]);
}//计算t[x]
for(int i=h[x];i;i=pre[i])
{
int v=to[i];
if(v==fa)continue;
f[x]+=f[v]+t[x]-t[v]-len[i];
}//计算f[x]
}
int main()
{
scanf("%d%d",&n,&rt);
for(int i=1;i<n;i++)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
ins(x,y,z);ins(y,x,z);
}
dfs(rt,0);
printf("%lld\n",f[rt]);return 0;
}