DP
题目讲得很清楚"对于电路板的任何两个节点,都存在且仅存在一条通路".
所以电路板是一颗树
题目要求叶子节点时态一致
如果从根开始枚举时间肯定超时
考虑反过来
从叶子节点开始考虑时间
容易注意到
对于一个子树的根 root 来说
不管上面用了多久把信息传下来
要让它的儿子收到信息的时间相同
就必须让 root 到各个儿子的距离相等
如果一个子树已经调好了
那么以后也不会再去更改
即无后效性
所以考虑DP
对于一个非叶子节点,要让它到各个儿子的距离相等
那么显然最节省的方案就是
让它到各个儿子的距离改成它最远的儿子的距离
所以得出状态转移方程:
设f[ i ]为 当以 i 为根的子树的时态同步时,从它的叶子到 i 需要的时间
则
f[ i ]=max(f[ i ],f[ u ]+dis[ i ][ u ]) ( u为 i 的儿子,dis[ i ][ u ]为 i 到 u 的距离)
而答案就在更新f[ i ] 的时候顺便累加一下就好了
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=500007; vector <int> v[N],g[N]; //用vector 存图,反正不会超时 int n,rt;//rt 为根节点 long long f[N],ans;//f如上所述,ans存答案 inline void dfs(int x,int fa)//fa 存 x 的父亲 { int len=v[x].size(); for(int i=0;i<len;i++) { int u=v[x][i]; if(u==fa) continue;//如果是父亲就跳过 dfs(u,x);//否则先更新儿子节点 f[x]=max(f[x],f[u]+g[x][i]);//更新当前节点 } for(int i=0;i<len;i++) { int u=v[x][i]; if(u==fa) continue;//如果是父亲就跳过 ans+=(f[x]-f[u]-g[x][i]);//累加答案 } } int main() { int a,b,c; cin>>n>>rt; for(int i=1;i<n;i++) { a=read(); b=read(); c=read(); v[a].push_back(b); g[a].push_back(c); v[b].push_back(a); g[b].push_back(c); }//存边 dfs(rt,rt); cout<<ans; return 0; }