#include<fstream>
#include<vector>
#include<deque>
using namespace std;
typedef int var;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
#define MAXN 50001
#define INF (1<<28)
struct Rmq {
var rmq, sol;
const bool operator<(const Rmq &t) const {
return rmq < t.rmq;
}
Rmq(var a, var b) {
sol = a;
rmq = b;
}
Rmq(){}
};
vector<var> G[MAXN];
deque<var> PATH[MAXN];
var PathP[MAXN];
var IN[MAXN], HEAVY[MAXN];
var V[MAXN], POZ[MAXN];
bool VIZ[MAXN];
var LOG[MAXN], N[MAXN];
var n, m, t;
var paths;
var *TREES[MAXN];
var BEG[MAXN];
Rmq RMQ[20][3*MAXN];
void dfs(var node, var depth) {
VIZ[node] = 1;
HEAVY[node] = 1;
RMQ[0][++t] = Rmq(node, depth);
BEG[node] = t;
var best = -1, in;
for(auto vec : G[node]) {
if(!VIZ[vec]) {
dfs(vec, depth+1);
RMQ[0][++t] = Rmq(node, depth);
if(HEAVY[vec] > best) {
best = HEAVY[vec];
in = IN[vec];
}
PathP[IN[vec]] = node;
HEAVY[node] += HEAVY[vec];
}
}
if(best == -1) {
IN[node] = ++paths;
PATH[paths].push_front(node);
} else {
IN[node] = in;
PATH[in].push_front(node);
}
}
void build_log() {
for(var i=2; i<=3*n; i++) {
LOG[i] = LOG[i/2] + 1;
}
}
void build_rmq() {
var n = t;
for(var i=1; (1<<i) <= n; i++) {
for(var j=1; j+(1<<i)-1<=n; j++) {
RMQ[i][j] = min(RMQ[i-1][j], RMQ[i-1][j+(1<<(i-1))]);
}
}
}
var lca(var a, var b) {
a = BEG[a];
b = BEG[b];
if(a > b) swap(a, b);
var l = LOG[b-a+1];
auto rez = min(RMQ[l][a], RMQ[l][b-(1<<l)+1]);
return rez.sol;
}
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(l > e || r < b)
return -INF;
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 afla_max(var node, var parent) {
var cur_path = IN[node];
var end_index = POZ[node];
var res = -INF;
while(cur_path != IN[parent]) {
res = max(res, query(cur_path, 1, 1, N[cur_path], 1, end_index));
node = PathP[cur_path];
end_index = POZ[node];
cur_path = IN[node];
}
res = max(res, query(cur_path, 1, 1, N[cur_path], POZ[parent], POZ[node]));
return res;
}
void afis(var ind, var node, var b, var e) {
var *TREE = TREES[ind];
fout<<"["<<b<<" " << e<<"] : "<<TREE[node]<<'\n';
if(b == e) return;
var m = (b+e)/2;
afis(ind, node*2, b, m);
afis(ind, node*2+1, m+1, e);
}
int main() {
var a, b;
fin>>n>>m;
for(var i=1; i<=n; i++) {
fin>>V[i];
}
var e = n-1;
while(e--) {
fin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
dfs(1, 0);
build_log();
build_rmq();
for(var i=1; i<=paths; i++) {
PATH[i].push_front(0);
for(var j=1; j<PATH[i].size(); j++) {
POZ[PATH[i][j]] = j;
}
}
/*
for(var i=1; i<=paths; i++) {
fout<<"path "<<i<<" : ";
for(auto node : PATH[i]) {
fout<<node<<" ";
}
fout<<endl;
}
*/
for(var i=1; i<=paths; i++) {
N[i] = PATH[i].size() - 1;
TREES[i] = new var[3*N[i]];
build_tree(i, 1, 1, N[i]);
}
/*
for(var i=1; i<=paths; i++) {
fout<<"ARBORELE "<<i<<" : \n";
afis(i, 1, 1, N[i]);
}
*/
var type, lc;
while(m--) {
fin>>type>>a>>b;
if(type == 0) {
update(IN[a], 1, 1, N[IN[a]], POZ[a], b);
} else {
var lc = lca(a, b);
fout << max(afla_max(a, lc), afla_max(b, lc)) << '\n';
}
}
return 0;
}