import java.io.OutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Arrays; import java.io.BufferedWriter; import java.util.InputMismatchException; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.stream.Stream; import java.io.Writer; import java.io.OutputStreamWriter; import java.util.Comparator; import java.io.InputStream; /** * Built using CHelper plug-in * Actual solution is at the top */ public class Main { public static void main(String[] args) { InputStream inputStream = System.in; OutputStream outputStream = System.out; InputReader in = new InputReader(inputStream); OutputWriter out = new OutputWriter(outputStream); Tree solver = new Tree(); int testCount = Integer.parseInt(in.next()); for (int i = 1; i <= testCount; i++) solver.solve(i, in, out); out.close(); } static class Tree { public static final int SQ = 333; public static final int MAXL = 19; public static final long INF = 1L << 60; int n; int q; long[] c; List[] graph; HashSet super_nodes; HashSet all_super_nodes; boolean[] vis; int[] super_par; int[] which; long[] add; List[] vals; int[] p; int[] d; int[][] anc; ArrayList special; boolean[] is_special; public void solve(int testNumber, InputReader in, OutputWriter out) { n = in.nextInt(); q = in.nextInt(); c = in.readLongArray(n); graph = LUtils.genArrayList(n); for (int i = 0; i < n - 1; i++) { int x = in.nextInt() - 1, y = in.nextInt() - 1; graph[x].add(y); graph[y].add(x); } anc = new int[MAXL][n]; p = new int[n]; d = new int[n]; special = new ArrayList<>(); is_special = new boolean[n]; dfs(0, -1); super_nodes = new HashSet<>(); for (int x : special) { int cur = p[x]; while (cur != -1) { if (is_special[cur]) { super_nodes.add(cur); break; } cur = p[cur]; } } super_nodes.add(0); all_super_nodes = new HashSet<>(super_nodes); vis = new boolean[n]; for (int x : super_nodes) { if (x == 0) continue; int cur = p[x]; while (!super_nodes.contains(cur) && !vis[cur]) { vis[cur] = true; cur = p[cur]; } if (!super_nodes.contains(cur)) { all_super_nodes.add(cur); } } vals = LUtils.genArrayList(n); which = new int[n]; Arrays.fill(which, -1); super_par = new int[n]; Arrays.fill(super_par, -1); int idx = 0; for (int x : all_super_nodes) { if (x == 0) continue; int cur = x; while (true) { vals[idx].add(cur); which[cur] = idx; cur = p[cur]; if (all_super_nodes.contains(cur)) { break; } } vals[idx].sort(Comparator.comparingLong(gg -> c[gg])); super_par[idx] = cur; idx++; } add = new long[n]; while (q-- > 0) { int type = in.nextInt(); if (type == 1) { int u = in.nextInt() - 1, v = in.nextInt() - 1; long x = in.nextLong(); update(u, v, x); } else { int u = in.nextInt() - 1, v = in.nextInt() - 1; long x = in.nextLong(); long ans = query(u, v, x); out.println(ans >= INF ? -1 : ans); } } } void dfs(int node, int par) { p[node] = par; d[node] = par == -1 ? 0 : (d[par] + 1); anc[0][node] = par; for (int i = 1; i < MAXL; i++) { anc[i][node] = anc[i - 1][node] == -1 ? -1 : anc[i - 1][anc[i - 1][node]]; } if (d[node] % SQ == 0) { special.add(node); is_special[node] = true; } for (int next : graph[node]) { if (next == par) continue; dfs(next, node); } } int lca(int x, int y) { if (d[x] < d[y]) { int t = x; x = y; y = t; } int diff = d[x] - d[y]; for (int i = 0; i < MAXL; i++) { if (((diff >> i) & 1) == 1) { x = anc[i][x]; } } if (x == y) return x; for (int i = MAXL - 1; i >= 0; i--) { if (anc[i][x] != anc[i][y]) { x = anc[i][x]; y = anc[i][y]; } } return anc[0][x]; } void update(int u, int v, long x) { int l = lca(u, v); updateUp(u, l, x); updateUp(v, l, x); c[l] += x; if (which[l] != -1) upd(which[l]); } void updateUp(int u, int l, long x) { HashSet toUpdate = new HashSet<>(); while (u != l) { if (all_super_nodes.contains(u)) { if (d[super_par[which[u]]] >= d[l]) { add[which[u]] += x; u = super_par[which[u]]; } else { toUpdate.add(which[u]); c[u] += x; u = p[u]; } } else { if (which[u] != -1) toUpdate.add(which[u]); c[u] += x; u = p[u]; } } for (int g : toUpdate) { upd(g); } } void upd(int idx) { vals[idx].sort(Comparator.comparingLong(gg -> c[gg])); } long query(int u, int v, long x) { int l = lca(u, v); long res = Math.min(queryUp(u, l, x), queryUp(v, l, x)); long t = c[l] + (which[l] == -1 ? 0 : add[which[l]]); if (t >= x) res = Math.min(res, t); return res; } long queryUp(int u, int l, long x) { long res = INF; while (u != l) { if (all_super_nodes.contains(u)) { if (d[super_par[which[u]]] >= d[l]) { res = Math.min(res, query(which[u], x)); u = super_par[which[u]]; } else { if (c[u] + add[which[u]] >= x) res = Math.min(res, c[u] + add[which[u]]); u = p[u]; } } else { long t = c[u] + (which[u] == -1 ? 0 : add[which[u]]); if (t >= x) res = Math.min(res, t); u = p[u]; } } return res; } long query(int idx, long x) { int lo = 0, hi = vals[idx].size(); while (lo < hi) { int mid = (lo + hi) / 2; if (c[vals[idx].get(mid)] + add[idx] < x) { lo = mid + 1; } else { hi = mid; } } return lo == vals[idx].size() ? INF : (c[vals[idx].get(lo)] + add[idx]); } } static class LUtils { public static List[] genArrayList(int size) { return Stream.generate(ArrayList::new).limit(size).toArray(List[]::new); } } static class InputReader { private InputStream stream; private byte[] buf = new byte[1 << 16]; private int curChar; private int numChars; public InputReader(InputStream stream) { this.stream = stream; } public long[] readLongArray(int tokens) { long[] ret = new long[tokens]; for (int i = 0; i < tokens; i++) { ret[i] = nextLong(); } return ret; } public int read() { if (this.numChars == -1) { throw new InputMismatchException(); } else { if (this.curChar >= this.numChars) { this.curChar = 0; try { this.numChars = this.stream.read(this.buf); } catch (IOException var2) { throw new InputMismatchException(); } if (this.numChars <= 0) { return -1; } } return this.buf[this.curChar++]; } } public int nextInt() { int c; for (c = this.read(); isSpaceChar(c); c = this.read()) { ; } byte sgn = 1; if (c == 45) { sgn = -1; c = this.read(); } int res = 0; while (c >= 48 && c <= 57) { res *= 10; res += c - 48; c = this.read(); if (isSpaceChar(c)) { return res * sgn; } } throw new InputMismatchException(); } public long nextLong() { int c; for (c = this.read(); isSpaceChar(c); c = this.read()) { ; } byte sgn = 1; if (c == 45) { sgn = -1; c = this.read(); } long res = 0L; while (c >= 48 && c <= 57) { res *= 10L; res += (long) (c - 48); c = this.read(); if (isSpaceChar(c)) { return res * (long) sgn; } } throw new InputMismatchException(); } public String next() { int c; while (isSpaceChar(c = this.read())) { ; } StringBuilder result = new StringBuilder(); result.appendCodePoint(c); while (!isSpaceChar(c = this.read())) { result.appendCodePoint(c); } return result.toString(); } public static boolean isSpaceChar(int c) { return c == 32 || c == 10 || c == 13 || c == 9 || c == -1; } } static class OutputWriter { private final PrintWriter writer; public OutputWriter(OutputStream outputStream) { writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream))); } public OutputWriter(Writer writer) { this.writer = new PrintWriter(writer); } public void close() { writer.close(); } public void println(long i) { writer.println(i); } } }