#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMAX = 1e5 + 5;
const int MMAX = 1e5 + 5;
int n, m;
int v[NMAX];
vector<int> g[NMAX];
int lant[NMAX], posl[NMAX];
vector<int> a[NMAX];
vector<int> arb[NMAX];
int h[NMAX], sons[NMAX], father[NMAX];
void read() {
fin >> n >> m;
for(int i = 1; i <= n ; ++i)
fin >> v[i];
for(int i = 1 ; i < n ; ++i) {
int x, y; fin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
}
void dfs(int node, int fath) {
h[node] = h[fath] + 1;
int heaviestChildren = -1;
for(int x : g[node])
if(x != fath) {
dfs(x, node);
sons[node] += sons[x];
if(heaviestChildren == -1)
heaviestChildren = x;
if(sons[x] > sons[heaviestChildren])
heaviestChildren = x;
}
sons[node]++;
if(g[node].size() == 1 && node != 1) { //frunza
heaviestChildren = node;
lant[node] = node;
}
lant[node] = lant[heaviestChildren];
a[lant[node]].push_back(node);
posl[node] = a[lant[node]].size() - 1;
}
void dfs2(int node, int fath) {
if(lant[node] != lant[fath])
father[lant[node]] = fath;
for(int x : g[node])
if(x != fath)
dfs2(x, node);
}
void construct(int l, int node, int st, int dr) {
if(st == dr) {
arb[l][node] = a[l][st];
return ;
}
int mid = (st + dr) / 2;
construct(l, node * 2, st, mid);
construct(l, node * 2 + 1, mid + 1, dr);
arb[l][node] = arb[l][node * 2];
if(v[ arb[l][node] ] < v[ arb[l][node * 2 + 1] ])
arb[l][node] = arb[l][node * 2 + 1];
}
int query(int l, int node, int st, int dr, int left, int right) {
//caut in intervalul [left, rright]
if(left <= st && dr <= right)
return arb[l][node];
int mid = (st + dr) / 2;
int indmin1 = -1, indmin2 = -1;
//st mid dr
if(left <= mid)
indmin1 = query(l, node * 2, st, mid, left, right);
if(mid + 1 <= right)
indmin2 = query(l, node * 2 + 1, mid + 1, dr, left, right);
if(indmin1 != -1 && indmin2 != -1) {
if(v[indmin1] < v[indmin2])
return indmin2;
else
return indmin1;
} else return max(indmin1, indmin2);//unul este diferit -1
}
void constructDecompos() {
dfs(1, 0);
dfs2(1, 0);
/*
for(int i = 2 ; i <= n ; ++i)
if(g[i].size() == 1) {
for(int x : a[i])
cout << x << ' ' << lant[x] << " ";
cout << " " << father[lant[i]] << '\n';
}
*/
for(int i = 2; i <= n ; ++i)
if(a[i].size() > 0) {
arb[i].reserve(a[i].size() * 4 + 5);
construct(i, 1, 0, a[i].size() - 1);
}
}
void update(int l, int node, int st, int dr, int pos, int value) {
if(st == dr)
return ;
int mid = (st + dr) / 2;
if(pos <= mid)
update(l, node * 2 , st, mid, pos, value);
else
update(l, node * 2 + 1, mid + 1, dr, pos, value);
arb[l][node] = arb[l][node * 2];
if(v[ arb[l][node] ] < v[ arb[l][node * 2 + 1] ])
arb[l][node] = arb[l][node * 2 + 1];
}
void solve() {
constructDecompos();
while(m--) {
int x, y, t;
fin >> t >> x >> y;
if(t == 0) {
v[x] = y;
update(lant[x], 1, 0, a[lant[x]].size() - 1, posl[x], y);
}
else {
int ans = v[y];//cand se ajunge in radacina ambele sun egale
//dar nu se in considerare nodul curent
while(x != y) {
if(lant[x] == lant[y]) {
if(posl[x] > posl[y])
swap(x, y);
int q = query(lant[x], 1, 0, a[lant[x]].size() - 1, posl[x], posl[y]);
ans = max(ans, v[q]);
x = y;
} else {
if(h[father[lant[x]]] < h[father[lant[y]]])
swap(x, y);
int q = query(lant[x], 1, 0, a[lant[x]].size() - 1, posl[x], a[lant[x]].size() - 1);
ans = max(ans, v[q]);
x = father[lant[x]];
}
}
fout << ans << '\n';
}
}
}
int main() {
read(); solve();
return 0;
}