警钟撅烂
查看原帖
警钟撅烂
726577
yemuzhe楼主2024/4/17 16:06
  1. 在把根换到儿子时也要把作为中间点的情况加上当前点的贡献,包括最大值和次大值!

  2. 要开 long long!虽然答案不会爆 int,但是要防止减法溢出。

易错点在代码中标明:

#include <cstdio>
#define N 200005
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;

const int inf = 2e9;

int n, id[N];
int tot, head[N], nxt[N * 2], ver[N * 2], e[N * 2];
long long ans, f[N][2], ff[N]; // 不开 long long 见祖宗

void insert (int x, int y, int z)
{
	ver[++ tot] = y, e[tot] = z;
	nxt[tot] = head[x], head[x] = tot;
	return ;
}

void dp1 (int x, int fa)
{
	f[x][1] = ff[x] = -inf;
	for (int i = head[x], y; i; i = nxt[i])
	{
		if ((y = ver[i]) == fa) continue;
		dp1 (y, x), f[x][0] += max (f[y][0], f[y][1] + e[i]);
	}
	for (int i = head[x], y; i; i = nxt[i])
	{
		if ((y = ver[i]) == fa) continue;
		int now = f[x][0] + f[y][0] + e[i] - max (f[y][0], f[y][1] + e[i]);
		if (now > f[x][1]) ff[x] = f[x][1], f[x][1] = now, id[x] = y;
		else if (now > ff[x]) ff[x] = now;
	}
	return ;
}

void dp2 (int x, int fa)
{
	ans = max (ans, f[x][0]);
	for (int i = head[x], y; i; i = nxt[i])
	{
		if ((y = ver[i]) == fa) continue;
		int f0 = f[x][0], f1 = f[x][1];
		f[x][0] -= max (f[y][0], f[y][1] + e[i]);
		if (id[x] != y) f[x][1] -= max (f[y][0], f[y][1] + e[i]);
		else f[x][1] = ff[x] - max (f[y][0], f[y][1] + e[i]);
		f[y][0] += max (f[x][0], f[x][1] + e[i]);
		f[y][1] += max (f[x][0], f[x][1] + e[i]); // 要记得加
		ff[y] += max (f[x][0], f[x][1] + e[i]); // 要记得加
		int now = f[y][0] + f[x][0] + e[i] - max (f[x][0], f[x][1] + e[i]);
		if (now > f[y][1]) ff[y] = f[y][1], f[y][1] = now, id[y] = x;
		else if (now > ff[y]) ff[y] = now;
		dp2 (y, x), f[x][0] = f0, f[x][1] = f1;
	}
	return ;
}

int main ()
{
	scanf ("%d", &n);
	for (int i = 1, x, y, z; i < n; i ++)
	{
		scanf ("%d%d%d", &x, &y, &z);
		insert (x, y, z), insert (y, x, z);
	}
	dp1 (1, 0), dp2 (1, 0);
	printf ("%lld", ans);
	return 0;
}
2024/4/17 16:06
加载中...