#include <fstream>
#include <vector>
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
const int nmax = 1e5 + 5;
int maxx = 0;
int n;
vector <int> edge[nmax];
int v[nmax], invliniarizare[nmax], depth[nmax], parent[nmax], stsize[nmax], head[nmax];
vector <int> liniarizare;
int aint[2 * nmax];
void aint_update(int node, int st, int dr, int poz, int val)
{
if(st == dr){
aint[node] = val;
return ;
}
int med = (st + dr) / 2;
if(poz <= med)
aint_update(2 * node, st, med, poz, val);
else
aint_update(2 * node + 1, med + 1, dr, poz, val);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
int aint_query(int node, int st, int dr, int gst, int gdr)
{
if(gst == st and gdr == dr)
return aint[node];
int med = (st + dr) / 2;
if(gst > med)
return aint_query (2 * node + 1, med + 1, dr, gst, gdr);
if(gdr <= med)
return aint_query (2 * node, st, med, gst, gdr);
return max(aint_query(2 * node, st, med, gst, med), aint_query(2 * node + 1, med + 1, dr, med + 1, gdr));
}
void update(int a, int val)
{
aint_update(1, 1, n, invliniarizare[a], val);
}
int query(int a, int b)
{
if(head[a] == head[b]){
if(depth[a] > depth[b]) swap(a, b);
return aint_query(1, 1, n, a, b);
}
if(depth[head[a]] <= depth[head[b]])
swap(a, b);
return max(aint_query(1, 1, n, invliniarizare[head[a]], invliniarizare[a]), query(parent[head[a]], b));
}
void dfs(int node, int tata)
{
stsize[node] = 1;
depth[node] = depth[tata] + 1;
parent[node] = tata;
for(int i = 0; i < edge[node].size(); i++){
int fiu = edge[node][i];
if(fiu == tata)
continue;
dfs(fiu, node);
stsize[node] += stsize[fiu];
}
}
void decompose(int node, int cnt_head)
{
head[node] = cnt_head;
liniarizare.push_back(node);
invliniarizare[node] = liniarizare.size();
int heavy = 0;
for(int i = 0; i < edge[node].size(); i++)
if(edge[node][i] != parent[node] and stsize[edge[node][i]] > stsize[heavy])
heavy = edge[node][i];
if(!heavy)
return ;
decompose(heavy, cnt_head);
for(int i = 0; i < edge[node].size(); i++)
if(edge[node][i] != parent[node] and edge[node][i] != heavy)
decompose(edge[node][i], edge[node][i]);
}
int main()
{
int i, j, q;
cin >> n >> q;
for(i = 1; i <= n; i++)
cin >> v[i];
for(i = 1; i <= n - 1; i++){
int x, y;
cin >> x >> y;
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs(1, 1);
decompose(1, 1);
for(i = 1; i <= n; i++){
if(i == 3)
int x;
aint_update(1, 1, n, invliniarizare[i], v[invliniarizare[i]]);
}
for(i = 1; i <= q; i++){
int t, a, b;
cin >> t >> a >> b;
if(t == 0)
update(a, b);
else{
maxx = 0;
cout << query(a, b) << "\n";
}
}
return 0;
}