【树形 DP】AcWing 325. 计算机

我的解法可能比较诡异😰

分析

题意是给你一棵带权的树,求每个点到其它点的最长路。

因为需要求每个点的,因此考虑换根 dp。

考虑维护信息:\(f[u]\)\(u\) 到其它点的最长路(也就是所求答案),\(g[u]\)\(u\) 到其它点次长路,\(d_1[u]\) 表示 \(u\) 到其所在子树上的点的最长路,\(d_2[u]\) 表示到其所在子树的点的次长路,\(son[u]\) 表示 \(u\) 所在的最长路所经过的子节点(如果最长路不经过子节点则设为 \(0\))。

然后我们做两次 dp(约定 \(1\) 号点为根):

  • 第一次将 \(d_1, d_2, son\) 处理出来,同时我们得到了 \(f[1], g[1]\)
  • 第二次更新 \(f, g, son\),利用父节点 \(u\) 更新子节点 \(go\),其中核心部分是分类讨论:如果 \(go\)\(u\)\(son[u]\),那么就需要注意不能再使用 \(f[u]\)\(go\)\(f,g\) 值进行更新。

更多细节见代码:

// Problem: 计算机
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/327/
// Memory Limit: 30 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=1e4+5, M=N<<1;

struct Edge{
	int to, next, w;
}e[M];

int h[N], tot;

void add(int u, int v, int w){
	e[tot].to=v, e[tot].w=w, e[tot].next=h[u], h[u]=tot++;
}

int n;

int d1[N], d2[N], son[N];

void dp1(int u, int fa){
	for(int i=h[u]; ~i; i=e[i].next){
		int go=e[i].to;
		if(go==fa) continue;
		dp1(go, u);
		
		int val=e[i].w+d1[go];
		if(val>=d1[u]) d2[u]=d1[u], d1[u]=val, son[u]=go;
		else d2[u]=max(d2[u], val);
	}
}

int f[N], g[N];

void dp2(int u, int fa){
	for(int i=h[u]; ~i; i=e[i].next){
		int go=e[i].to;
		if(go==fa) continue;
		
		if(go==son[u]){
			if(d1[go]<=e[i].w+g[u]) son[go]=0;
			f[go]=max(d1[go], e[i].w+g[u]);
			if(son[go]) g[go]=max(d2[go], e[i].w+g[u]);
			else g[go]=d1[go];
		}
		else{
			if(d1[go]<=e[i].w+f[u]) son[go]=0;
			f[go]=max(d1[go], e[i].w+f[u]);
			if(son[go]) g[go]=max(d2[go], e[i].w+f[u]);
			else g[go]=d1[go];
		}
		
		dp2(go, u);
	}
}

int main(){
	while(cin>>n){
		rep(i,1,n) h[i]=-1, d1[i]=d2[i]=f[i]=g[i]=son[i]=0;
		rep(i,2,n){
			int u, w; read(u), read(w);
			add(i, u, w), add(u, i, w);
		}
		
		dp1(1, -1);
		f[1]=d1[1], g[1]=d2[1];
		dp2(1, -1);
		
		rep(i,1,n) cout<<f[i]<<endl;
	}
	return 0;
}
posted @ 2022-03-30 11:42  HinanawiTenshi  阅读(24)  评论(0编辑  收藏  举报