#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 5e5 + 5;
const ll NEG_INF = -1e18;
ll w[M]; // weight of each node
ll dp[M]; // best value of dp[u] = max downward path from u
ll res;
vector<pair<int, ll>> tree[M]; // adjacency list: (neighbor, cost)
// Post-order DFS to compute dp values and best cycles
void dfs(int u, int parent) {
ll best1 = 0, best2 = 0; // top 2 deltas for cycle turning at u
dp[u] = w[u]; // base case: path is just the node itself
for (auto [v, cost] : tree[u]) {
if (v == parent) continue;
dfs(v, u);
ll delta = dp[v] - 2 * cost;
if (delta > best1) {
best2 = best1;
best1 = delta;
} else if (delta > best2) {
best2 = delta;
}
// Update dp[u] for max downward path
dp[u] = max(dp[u], w[u] + delta);
}
// Try to form a cycle using two best branches under u
res = max(res, w[u] + best1 + best2);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
// Read node weights
for (int i = 1; i <= n; ++i) {
cin >> w[i];
tree[i].clear();
dp[i] = NEG_INF;
}
// Read edges
for (int i = 0; i < n - 1; ++i) {
int u, v;
ll c;
cin >> u >> v >> c;
tree[u].emplace_back(v, c);
tree[v].emplace_back(u, c);
}
res = NEG_INF;
dfs(1, 0);
cout << res << '\n';
}
return 0;
}