题解——[ZJOI2007]时态同步(树形结构)

题解——[ZJOI2007]时态同步(树形结构)

*为何要写DP?,不是摆明的水题吗 *


题面

Description
小Q在电子工艺实习课上学习焊接电路板。一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3….进行标号。电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两个节点,都存在且仅存在一条通路(通路指连接两个元件的导线序列)。

在电路板上存在一个特殊的元件称为“激发器”。当激发器工作后,产生一个激励电流,通过导线传向每一个它所连接的节点。而中间节点接收到激励电流后,得到信息,并将该激励电流传向与它连接并且尚未接收到激励电流的节点。最终,激烈电流将到达一些“终止节点”――接收激励电流之后不再转发的节点。

激励电流在导线上的传播是需要花费时间的,对于每条边e,激励电流通过它需要的时间为t
,而节点接收到激励电流后的转发可以认为是在瞬间完成的。现在这块电路板要求每一个“终止节点”同时得到激励电路――即保持时态同步。由于当前的构造并不符合时态同步的要求,故需要通过改变连接线的构造。目前小QQ有一个道具,使用一次该道具,可以使得激励电流通过某条连接导线的时间增加一个单位。请问小Q最少使用多少次道具才可使得所有的“终止节点”时态同步?

Input
root + 一棵树

Output

一个整数表示最低次数

in.1
3
1
1 2 1
1 3 3

out.1
2

数据范围与约定

对于100%数据,n<=1e5 , t<=1e6

思路

主要思路

由于边值只能增不能减,我们考虑自底向上对每个节点 i 进行处理,i 向非 fa 节点连的边一定等长 , 否则无论如何都不能满足 。 我们只要对每个节点求出其儿子的 max 值,并更新其他儿子 , 更新之差的总和就是答案 。

细节:
注意dis开 long long
要不断用 dis[] 更新 , 不能只用该点所连的边权 w[ i ] ,因为儿子节点到其对应的叶节点的距离并不相同

错误代码

void  dfs( int u , int fa ){
	ll sum = 0LL , ma = 0LL , cnt = 0LL ;
	for( int i = head[ u ] ; i ; i = nex[ i ] ){
		if( to[ i ] == fa )continue ;
		dfs( to[ i ] , u ) ;
		sum += (ll)w[ i ] , ma = max( (ll)w[ i ] , ma ) , cnt++ ;
	}
	ans += ma*cnt - sum ;
}

正确写法

void  dfs( int u , int fa ){
	ll sum = 0LL , ma = 0LL ;
	for( int i = head[ u ] ; i ; i = nex[ i ] ){
		if( to[ i ] == fa )continue ;
		dfs( to[ i ] , u ) ;
		ma = max( dis[ to[i] ] + w[ i ] , ma ) ;//统计最大值
	}
	dis[ u ] = ma ; //更新dis[ u ]
	for( int i = head[ u ] ; i ; i = nex[ i ] ){
		if( to[ i ] == fa )continue ;
		ans += dis[ u ] - w[ i ] - dis[ to[ i ] ] ;  //统计贡献
	}
}

完整代码

#include<bits/stdc++.h>
using namespace std ;
#define ll long long
const int MAXN = 500005 ;
inline int read(){
	int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ; 
	while(g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
int N , root , to[ MAXN*2 ] , nex[ MAXN*2 ] , head[ MAXN ] , w[ MAXN*2 ] , tot = 1;
ll ans = 0LL , dis[ MAXN ];
void add( int x , int y , int z){
	to[ ++tot ] = y , nex[ tot ] = head[ x ] , w[ tot ] = z , head[ x ] = tot ;
} 
void  dfs( int u , int fa ){
	ll sum = 0LL , ma = 0LL ;
	for( int i = head[ u ] ; i ; i = nex[ i ] ){
		if( to[ i ] == fa )continue ;
		dfs( to[ i ] , u ) ;
		ma = max( dis[ to[i] ] + w[ i ] , ma ) ;
	}
	dis[ u ] = ma ; 
	for( int i = head[ u ] ; i ; i = nex[ i ] ){
		if( to[ i ] == fa )continue ;
		ans += dis[ u ] - w[ i ] - dis[ to[ i ] ] ;  
	}
}
int main(){
	N = read() , root = read() ; int m1 , m2 , m3 ;
	for( int i = 1 ;  i < N ; ++i ){
		m1 = read() , m2 = read() , m3 = read() ;
		add( m1 , m2 , m3 ) , add( m2 , m1 , m3 ) ;
	}
	dfs( root , root ) ;
	cout<<ans ;
	return 0 ;
}

如有不足,请大佬指出

原文地址:https://www.cnblogs.com/ssw02/p/11431951.html