#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 100000 + 10
/**
题目大意
树的每个节点 有一个权值(v) 边有一权值(cost)
经过一点获得v(仅一次) 经过一条边损失cost(多次)
求从各点出发 获得的最大值
思路
子树范围:
dp[u][0] 从u出发不回到u的最大值
dp[u][1] 从u出发回到u的最大值
dp[u][2] 从u出发不回到u的次大值
不包括自身权值
第一遍dfs求子树范围的dp(son->fa)
sum为u父节点方向(tree - 子树范围)不会到u的最大值;
sum1为u回到u的最大值
第二遍dfs求得(fa->son)
ans[u] = max(dp[u][0] + sum1, dp[u][1] + sum) + V[u]
*/
using namespace std;
struct Edge
{
int from, to, cost;
Edge(int f, int t, int c): from(f), to(t), cost(c) {}
};
vector<Edge> edges;
vector<int> g[MAXN];
void addEdge(int u, int v, int c)
{
int s = edges.size();
edges.push_back(Edge(u, v, c));
g[u].push_back(s);
edges.push_back(Edge(v, u, c));
g[v].push_back(s + 1);
}
int V[MAXN], dp[MAXN][3], id[MAXN];
// id[u] 子树范围由u出发不回到u 最后一次从u出发到达的子节点
void dfs(int u, int fa)
{
int v, temp = 0, temp1;
int tmp = 0;
for (int i = 0; i < g[u].size(); i++)
{
Edge e = edges[g[u][i]];
v = e.to;
if (v == fa)
continue;
dfs(v, u);
temp1 = MAX(0, dp[v][1] + V[v] - 2 * e.cost);
dp[u][1] += temp1;
/**
求次大
*/
if (MAX(0, dp[v][0] + V[v] - e.cost) - temp1 > temp)
{
tmp = temp;
temp = MAX(0, dp[v][0] + V[v] - e.cost) - temp1;
id[u] = v;
}
else if (MAX(0, dp[v][0] + V[v] - e.cost) - temp1 > tmp)
tmp = MAX(0, dp[v][0] + V[v] - e.cost) - temp1;
}
dp[u][0] = dp[u][1] + temp;
dp[u][2] = dp[u][1] + tmp;
}
int ans[MAXN];
void dfs1(int u, int fa, int sum, int sum1)
{
ans[u] = MAX(dp[u][0] + sum1, dp[u][1] + sum) + V[u];
int v, temp, temp1;
for (int i = 0; i < g[u].size(); i++)
{
Edge e = edges[g[u][i]];
v = e.to;
if (v == fa)
continue;
temp1 = MAX(0, sum1 + dp[u][1] + V[u] - MAX(0, dp[v][1] + V[v] - 2 * e.cost) - 2 * e.cost);
int tmp;
if (id[u] == v)
tmp = dp[u][2] - MAX(0, dp[v][1] + V[v] - 2 * e.cost);
else
tmp = dp[u][0] - MAX(0, dp[v][1] + V[v] - 2 * e.cost);
temp = MAX(0, MAX(sum + V[u] - e.cost + dp[u][1] - MAX(0, dp[v][1] + V[v] - 2 * e.cost), sum1 + V[u] - e.cost + tmp));
/**
u->v转移
v父节点范围内不回到v的最大值 先由v到达u 然后分两种
1. 由u到达u的fa后回到u 后由u到u除v外的子节点不回来(使用次大值)
2. u到u除v外的子节点回到u 后由u到达u的fa后不回
*/
dfs1(v, u, temp, temp1);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int t, n, kase = 0;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
edges.clear();
mem(dp, 0);
mem(id, 0);
rep1(i, n)
{
scanf("%d", V + i);
g[i].clear();
}
int u, v, c;
rep0(i, n - 1)
{
scanf("%d %d %d", &u, &v, &c);
addEdge(u, v, c);
}
dfs(1, -1);
dfs1(1, -1, 0, 0);
printf("Case #%d:\n", ++kase);
rep1(i, n)
printf("%d\n", ans[i]);
}
return 0;
}