[ZJOI2007] 时态同步
显然的一个建模是,每个叶子对应一个权值,代表比最晚的叶子早了多久,然后我们要做的就是给每条边赋上值,使得每个叶子到根的路径上的所有边权值和等于叶子的权值。
我们贪心的想一想,必然是离根越近的边赋值多的情况比较优(在保证同步的情况下),因为离根越近的边影响的叶子会更多。
而对于两个节点 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; }
我爱学习,学习使我快乐