HDU 2196 Computer

题目大意

%   给定一棵边带权树,你需要输出对于每个点而言,距离它最远的点和它的距离。
  数据范围  1 ⩽ n ⩽ 1 0 4 , 1 ⩽ w ( u , v ) ⩽ 1 0 9 1\leqslant n\leqslant 10^4,1\leqslant w_{(u,v)}\leqslant 10^9 1n104,1w(u,v)109

题解

%   无根树不好考虑,先钦定一个点为根节点。
%   考虑树形dp,定义 d o w n [ u ] down[u] down[u] 表示点 u u u 的子树中距离点 u u u 最远的点到点 u u u 的距离。则有 d o w n [ u ] = max ⁡ v ∈ s o n ( u ) { d o w n [ v ] + 1 } down[u]=\max_{v\in son(u)}\{down[v]+1\} down[u]=vson(u)max{down[v]+1}

%   求出后,我们考虑求出子树外的答案,定义 u p [ u ] up[u] up[u] 表示不考虑 u u u 点的子树,其余点到点 u u u 的最远的点到点 u u u 的距离,由于已经求出了 d o w n down down,这里的转移也不难。
u p [ u ] = max ⁡ { u p [ f a ( u ) ] + w ( u , f a ( u ) ) max ⁡ t ∈ s o n ( f a ( u ) ) , t ≠ u d o w n [ t ] + w ( t , f a ( u ) ) + w ( f a ( u ) , u ) up[u]=\max\begin{cases}up[fa(u)]+w_{(u,fa(u))}\\\max\limits_{t \in son(fa(u)),t\not=u}down[t]+w_{(t,fa(u))}+w_{(fa(u),u)}\end{cases} up[u]=maxup[fa(u)]+w(u,fa(u))tson(fa(u)),t=umaxdown[t]+w(t,fa(u))+w(fa(u),u)

%   上面那条是通过父亲直接转移,下面那条通过其他儿子通过父亲连到自己的。
  考虑如何线性求出下面哪条式子的值。若我们假设 f a ( u ) fa(u) fa(u) 的第 k k k 个儿子为 s o n ( f a ( u ) ) [ k ] son(fa(u))[k] son(fa(u))[k],则定义
p r e [ k ] = max ⁡ p = 1 k w ( s o n ( f a ( u ) [ p ] , f a ( u ) ) ) + d o w n [ s o n ( f a ( u ) ) [ p ] ] , f i x [ k ] = max ⁡ p = k ∣ s o n ( f a ( u ) ) ∣ w ( s o n ( f a ( u ) [ p ] , f a ( u ) ) ) + d o w n [ s o n ( f a ( u ) ) [ p ] ] pre[k]=\max_{p=1}^{k} w_{(son(fa(u)[p],fa(u)))}+down[son(fa(u))[p]],\\fix[k]=\max_{p=k}^{|son(fa(u))|} w_{(son(fa(u)[p],fa(u)))}+down[son(fa(u))[p]] pre[k]=p=1maxkw(son(fa(u)[p],fa(u)))+down[son(fa(u))[p]],fix[k]=p=kmaxson(fa(u))w(son(fa(u)[p],fa(u)))+down[son(fa(u))[p]]

%   若 u u u f a ( u ) fa(u) fa(u) 的第 s s s 个儿子,则转移可以写成 u p [ u ] = max ⁡ { u p [ f a ( u ) ] + w ( u , f a ( u ) ) s u f [ s − 1 ] + f i x [ s + 1 ] + w ( f a ( u ) , u ) up[u]=\max\begin{cases}up[fa(u)]+w_{(u,fa(u))}\\suf[s-1]+fix[s+1]+w_{(fa(u),u)}\end{cases} up[u]=max{up[fa(u)]+w(u,fa(u))suf[s1]+fix[s+1]+w(fa(u),u)

%   如此,我们考虑在访问 f a ( u ) fa(u) fa(u) 时,将 f a ( u ) fa(u) fa(u) 的每个儿子都算出来,如此递推,最后的答案便是 max ⁡ ( u p [ u ] , d o w n [ u ] ) \max(up[u],down[u]) max(up[u],down[u])。详见代码(变量和上述定义基本一致)。时间复杂度 Θ ( n ) \Theta(n) Θ(n)

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 10010
struct edge{
	int v,w,next;
}edges[maxn<<1];
int n,head[maxn],cnt=0;
void ins(int u,int v,int w){
	edges[++cnt]=(edge){v,w,head[u]};
	head[u]=cnt;
}
int down[maxn];
void dfs(int u,int fa=-1){
	down[u]=0;
	for(int i=head[u];i;i=edges[i].next){
		int v=edges[i].v;
		if(v==fa) continue;
		dfs(v,u);
		down[u]=max(down[u],down[v]+edges[i].w);
	}
}
int up[maxn],pre[maxn],suf[maxn],fix[maxn],son[maxn],wei[maxn];
void redfs(int u,int fa=-1){
	int cnt=0;
	for(int i=head[u];i;i=edges[i].next){ 
		int v=edges[i].v;
		if(v==fa) continue;
		up[v]=max(up[v],up[u]+edges[i].w);
		son[++cnt]=v;
		wei[cnt]=edges[i].w;
		pre[cnt]=max(pre[cnt-1],down[v]+edges[i].w);
	} fix[cnt+1]=0;
	for(int i=cnt;i>0;i--) fix[i]=max(fix[i+1],down[son[i]]+wei[i]);
	for(int i=1;i<=cnt;i++) up[son[i]]=max(up[son[i]],wei[i]+max(pre[i-1],fix[i+1]));
	for(int i=head[u];i;i=edges[i].next){
		int v=edges[i].v;
		if(v==fa) continue;
		redfs(v,u);
	}
}
signed main(){
	while(~scanf("%lld",&n)){
		memset(down,0,sizeof down);
		memset(pre,0,sizeof pre);
		memset(suf,0,sizeof suf);
		memset(fix,0,sizeof fix);
		memset(head,cnt=0,sizeof head);
		memset(up,0,sizeof up);
		for(int i=2,v,w;i<=n;i++){
			scanf("%lld%lld",&v,&w);
			ins(i,v,w);ins(v,i,w);
		} dfs(1); redfs(1); 
		for(int i=1;i<=n;i++)
			printf("%lld\n",max(up[i],down[i]));
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值