[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
",f[S]);
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/11258074.html