【树形 DP】AcWing 325. 计算机

我的解法可能比较诡异😰

分析

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

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

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

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

  • 第一次将 d1,d2,son 处理出来,同时我们得到了 f[1],g[1]
  • 第二次更新 f,g,son,利用父节点 u 更新子节点 go,其中核心部分是分类讨论:如果 gouson[u],那么就需要注意不能再使用 f[u]gof,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 @   HinanawiTenshi  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-03-30 【DP,位运算】 Bank Security Unification
点击右上角即可分享
微信分享提示