点对最大值 (换根DP)

Posted lesning

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了点对最大值 (换根DP)相关的知识,希望对你有一定的参考价值。

“科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛)

换根来一波

https://ac.nowcoder.com/acm/contest/5758/A

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
typedef long long ll;
const int maxn = 1e6 + 111;
ll list[maxn];
struct Node {
	int p;
	ll len;
	int nxt;
}G[2*maxn];
int head[maxn];


int z;
void add(int x, int y,ll len) {
	G[++z].p = y;
	G[z].nxt = head[x];
	G[z].len = len;
	head[x] = z;
}
ll dp[maxn];//最大
ll dp2[maxn];//第二大

int cal(int x, ll val) {//x节点放进去一个val
	if (val >= dp[x]) {
		dp2[x] = dp[x];
		dp[x] = val;
	}
	else {
		if (val >= dp2[x]) {
			dp2[x] = val;
		}
	}
	return 0;
}
int de[maxn];

int dfs1(int x, int fa) {
	for (int i = head[x]; i; i = G[i].nxt) {
		int p = G[i].p;
		ll ln = G[i].len;
		if (p == fa) continue;
		dfs1(p, x);
		ll a = list[x] + ln + list[p];  
		ll b = dp[p] - list[p] + ln + list[x];

		if (a > b) {
			cal(x, a);
		}
		else {
			cal(x, b);
		}
		
	}
	return 0;
}


int dfs2(int x, int fa) {
	for (int i = head[x]; i; i = G[i].nxt) {
		int p = G[i].p;
		ll ln = G[i].len;
		if (p == fa) continue;
		ll c = list[x] + list[p] + ln;
		
		if (de[p] == 1) {
			if (list[x] + ln + list[p] == dp[x]) {//在线上
				ll a = dp2[x] - list[x] + ln + list[p];
				a = max(a, c);
				cal(p,a);
			}
			else {
				ll a = dp[x] - list[x] + ln + list[p];
				a = max(a, c);
				cal(p, a);
			}
		}
		else {
			if (dp[p] - list[p] + ln + list[x] == dp[x]|| dp[x] == list[p] + list[x] + ln) {
				ll a = dp2[x] - list[x] + ln + list[p];
				a = max(a, c);
				cal(p, a);
			}
			else {
				ll a = dp[x] - list[x] + ln + list[p];

				a = max(a, c);

				cal(p, a);
			}
		}
		dfs2(p, x);
	}
	return 0;
}

int n, m;
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		for (int i = 0; i <= n; i++) {
			head[i] = 0;
			de[i] = 0;

			dp[i] = -1e18;
			dp2[i] = -1e18;
		}
		z = 0;

		int x;
		ll len;
		int be, en;
		for (int i = 2; i <= n; i++) {
			scanf("%d %lld", &x, &len);
			add(x, i, len);
			add(i, x, len);
			de[x]++;
			de[i]++;
			
		}

		for (int i = 1; i <= n; i++) {
			scanf("%lld", &list[i]);
			//dp[i] = 2 * list[i];
		}


		dfs1(1, -1);
		dfs2(1, -1);
	
		long long ans = -1e18;
		for (int i = 1; i <= n; i++) {
			
			ans = max(ans, dp[i]);
		}
		printf("%lld
", ans);
	}
	return 0;

}

/*
21312
11
1 2 1
2 4 4s
2 3 3
3 5 7
3 6 8
1 7 2
7 8 5
7 9 6
8 10 9
9 11 10
1 2 3 4 5 6 7 8 9 10 11


*/

  

 

以上是关于点对最大值 (换根DP)的主要内容,如果未能解决你的问题,请参考以下文章

HDU6567树的重心换根DP

换根dp9.22小偷

ABC222 F - Expensive Expense(树形dp换根)

poj3585 Accumulation Degree(换根dp)

换根DP

ABC223 G - Vertex Deletion(换根dp)