#include<fstream>
#include<vector>
#include<deque>
#include<algorithm>
using namespace std;
typedef int var;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
#define MAXN 100001
vector<var> G[MAXN];
vector<var> Path[MAXN];
var *Trees[MAXN];
var PathP[MAXN], Heavy[MAXN], Depth[MAXN], WhatPath[MAXN], WhatPos[MAXN], V[MAXN], N[MAXN];
var paths;
void dfs(var node, var depth) {
Depth[node] = depth;
Heavy[node] = 1;
var M = -1, N;
for(auto vec : G[node]) {
if(Depth[vec] == 0) {
dfs(vec, depth+1);
Heavy[node] += Heavy[vec];
PathP[WhatPath[vec]] = node;
if(M < Heavy[vec]) {
M = Heavy[vec];
N = WhatPath[vec];
}
}
}
if(M == -1) {
WhatPath[node] = ++paths;
} else {
WhatPath[node] = N;
}
Path[WhatPath[node]].push_back(node);
}
void build_tree(var ind, var node, var b, var e) {
var *Tree = Trees[ind];
if(b == e) Tree[node] = V[Path[ind][b]];
else {
var m = (b+e)/2;
build_tree(ind, node*2, b, m);
build_tree(ind, node*2+1, m+1, e);
Tree[node] = max(Tree[node*2], Tree[node*2+1]);
}
}
void update(var ind, var node, var b, var e, var poz, var val) {
var *Tree = Trees[ind];
if(b == e) {
Tree[node] = val;
} else {
var m = (b+e)/2;
if(poz <= m)
update(ind, node*2, b, m, poz, val);
else
update(ind, node*2+1, m+1, e, poz, val);
Tree[node] = max(Tree[node*2], Tree[node*2+1]);
}
}
var query(var ind, var node, var b, var e, var l, var r) {
var *Tree = Trees[ind];
if(b >= l && e <= r)
return Tree[node];
if(e<l || b>r) {
return -1;
}
var m = (b+e)/2;
return max(
query(ind, node*2, b, m, l, r),
query(ind, node*2+1, m+1, e, l, r)
);
}
var solve_for(var a, var b) {
var rez = -1;
var p1 = WhatPath[a], p2 = WhatPath[b];
while(p1 != p2) {
if(Depth[PathP[p1]] > Depth[PathP[p2]]) {
rez = max(rez, query(p1, 1, 1, N[p1], 1, WhatPos[a]));
a = PathP[p1];
p1 = WhatPath[a];
} else {
rez = max(rez, query(p2, 1, 1, N[p2], 1, WhatPos[b]));
b = PathP[p2];
p2 = WhatPath[b];
}
}
if(Depth[a] > Depth[b])
swap(a, b);
rez = max(rez, query(p1, 1, 1, N[p1], WhatPos[a], WhatPos[b]));
return rez;
}
int main() {
var n, m, a, b;
fin>>n>>m;
for(var i=1; i<=n; i++) {
fin>>V[i];
}
for(var i=2; i<=n; i++) {
fin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
dfs(1, 1);
//Some more preprocessing
PathP[WhatPath[1]] = 0;
for(var i=1; i<=paths; i++) {
Path[i].push_back(0);
N[i] = Path[i].size() - 1;
reverse(Path[i].begin(), Path[i].end());
for(var j=1; j<=N[i]; j++) {
WhatPos[Path[i][j]] = j;
}
Trees[i] = new var[4*N[i]];
build_tree(i, 1, 1, N[i]);
}
var type;
while(m--) {
fin>>type>>a>>b;
if(type == 0) {
update(WhatPath[a], 1, 1, N[WhatPath[a]], WhatPos[a], b);
} else {
fout<<solve_for(a, b)<<'\n';
}
}
}