//gpt
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 200000 + 5;
const int H = 18; // since 2^18 = 262144 > MAXN
int N;
vector<pair<int, int> > g[MAXN];
ll W[MAXN];
// centroid‐decomp template arrays
int sub[MAXN], cth[MAXN], ctp[MAXN];
// we won’t actually use dist[][] here, but it’s part of the template:
int dist_arr[MAXN][H + 1];
// 1) compute subtree sizes on the “active” (cth[v]==0) part
void dfs_siz(int u, int f) {
sub[u] = 1;
for (auto &e: g[u]) {
int v = e.first;
if (v == f || cth[v] != 0) continue;
dfs_siz(v, u);
sub[u] += sub[v];
}
}
// 2) find centroid of the component
int fc(int u, int f, int lim) {
for (auto &e: g[u]) {
int v = e.first;
if (v == f || cth[v] != 0) continue;
if (sub[v] > lim) return fc(v, u, lim);
}
return u;
}
// 3) (unused) compute dist[u][h]
void dfs_dist(int u, int f, int d, int h) {
dist_arr[u][h] = d;
for (auto &e: g[u]) {
int v = e.first;
if (v == f || cth[v] != 0) continue;
dfs_dist(v, u, d + 1, h);
}
}
// global answer
ll answer;
// collect for each node x in the subtree rooted at `u` (child of centroid):
// val[x] = accumulated sum (W along path) - 2*(sum of edge‐costs)
void dfs_collect(int u, int f, ll curr, vector<ll> &vals) {
vals.push_back(curr);
for (auto &e: g[u]) {
int v = e.first, c = e.second;
if (v == f || cth[v] != 0) continue;
dfs_collect(v, u, curr + W[v] - 2LL * c, vals);
}
}
// 4) modified decompose: integrates our “max‐path” logic at each centroid
void decompose(int entry, int parent = 0, int height = 1) {
// a) find centroid `cent`
dfs_siz(entry, 0);
int cent = fc(entry, 0, sub[entry] >> 1);
// b) (optional) fill dist_arr for this level:
dfs_dist(cent, 0, 0, height);
// c) compute all best paths that pass through `cent`
ll bestVal = LLONG_MIN;
for (auto &e: g[cent]) {
int v = e.first, c = e.second;
if (cth[v] != 0) continue;
// collect values in subtree `v`
vector<ll> vals;
// initialize with path just (cent->v)
dfs_collect(v, cent, W[v] - 2LL * c, vals);
// for each endpoint in this subtree, combine with bestVal from prior subtrees
for (ll d: vals) {
if (bestVal != LLONG_MIN) {
// path = (some x in other subtree) -> cent -> current node
answer = max(answer, bestVal + d + W[cent]);
}
}
// now absorb this subtree's endpoints
for (ll d: vals) {
bestVal = max(bestVal, d);
}
}
// d) mark centroid and record parent/height in centroid tree
cth[cent] = height;
ctp[cent] = parent;
// e) recurse on each remaining component
for (auto &e: g[cent]) {
int v = e.first;
if (cth[v] == 0) {
decompose(v, cent, height + 1);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
cin >> N;
for (int i = 1; i <= N; i++) {
cin >> W[i];
g[i].clear();
cth[i] = 0;
}
for (int i = 0; i < N - 1; i++) {
int u, v, c;
cin >> u >> v >> c;
g[u].emplace_back(v, c);
g[v].emplace_back(u, c);
}
answer = LLONG_MIN;
// start decomposition from node 1
decompose(1, 0, 1);
cout << answer << "\n";
}
return 0;
}