#pragma GCC optimize("O3")
#pragma GCC optimize("fast-math")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int dim = 1e5 + 5;
int n, v[dim], aint[4 * dim], queries, x, y, op, nod_height[dim], tata[dim], sz[dim], pozu[dim], pozudoi[dim], z, arb[dim];
vector<int>noduri[dim];
void dfs(int nod, int tat = 0)
{
tata[nod] = tat;
sz[nod] = 1;
nod_height[nod] = nod_height[tat] + 1;
for(auto it: noduri[nod])
{
if(it != tat)
{
dfs(it, nod);
sz[nod] += sz[it];
}
}
}
void dfsdoi(int nod)
{
int maxi = 0, idx = 0;
pozu[nod] = ++z;
pozudoi[z] = nod;
for(auto it : noduri[nod])
{
if(it != tata[nod] && sz[it] > maxi)
{
maxi = sz[it];
idx = it;
}
}
if(idx == 0)
{
return;
}
arb[idx] = arb[nod];
dfsdoi(idx);
for(auto it: noduri[nod])
{
if(it != tata[nod] && it != idx)
{
arb[it] = it;
dfsdoi(it);
}
}
}
void build(int nod, int st, int dr)
{
if(st == dr)
{
aint[nod] = v[pozudoi[st]];
}
else
{
int mid = (st + dr) / 2;
build(2 * nod, st, mid);
build(2 * nod + 1, mid + 1, dr);
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
}
void update(int nod, int st, int dr, int poz, int val)
{
if(st == dr)
{
aint[nod] = val;
return;
}
else
{
int mid = (st + dr) / 2;
if(poz <= mid)
{
update(2 * nod, st, mid, poz, val);
}
else
{
update(2 * nod + 1, mid + 1, dr, poz, val);
}
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
}
int query(int nod, int st, int dr, int poz, int val)
{
if(val < st || poz > dr)
{
return 0;
}
if(poz <= st && dr <= val)
{
return aint[nod];
}
else
{
int mid = (st + dr) / 2;
return max(query(2 * nod, st, mid, poz, val), query(2 * nod + 1, mid + 1, dr, poz, val));
}
}
int querydoi(int poz, int val)
{
if(arb[poz] == arb[val])
{
return query(1, 1, n, min(pozu[poz], pozu[val]), max(pozu[poz], pozu[val]));
}
if(nod_height[arb[poz]] < nod_height[arb[val]])
{
swap(poz, val);
}
int t = query(1, 1, n, pozu[arb[poz]], pozu[poz]);
return max(t, querydoi(tata[arb[poz]], val));
}
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int32_t main(int argc, char * argv[])
{
fin >> n >> queries;
for(int i = 1; i <= n; ++i)
{
fin >> v[i];
}
for(int i = 1; i < n; ++i)
{
fin >> x >> y;
noduri[x].push_back(y);
noduri[y].push_back(x);
}
dfs(1);
arb[1] = 1;
dfsdoi(1);
build(1, 1, n);
for(int i = 1; i <= queries; ++i)
{
fin >> op >> x >> y;
if(op == 0)
{
update(1, 1, n, pozu[x], y);
}
else
{
fout << querydoi(x, y) << '\n';
}
}
return 0;
}