#include<fstream>
#include<vector>
#include<algorithm>
#define NMAX 100005
using namespace std;
vector<int> G[NMAX];
vector<int> p[NMAX];
int A[4 * NMAX];
int n, m, x, y, op, qs, sol_path;
int np;
int value[NMAX];
int wg[NMAX], niv[NMAX], ps[NMAX];
int wp[NMAX], pf[NMAX], pfniv[NMAX];
int dcj[NMAX];
bool u[NMAX];
ifstream _cin("heavypath.in");
ofstream _cout("heavypath.out");
void update(int st, int dr, int nod, int poz, int upd, int decal)
{
if(st == dr)
{
A[nod + decal] = upd;
return;
}
int mij = st + (dr - st) / 2;
if(poz <= mij)
{
update(st, mij, 2 * nod, poz, upd, decal);
}else
{
update(mij + 1, dr, 2 * nod + 1, poz, upd, decal);
}
A[nod + decal] = max(A[2 * nod + decal], A[2 * nod + 1 + decal]);
}
void build(int st, int dr, int nod, int path, int decal)
{
if(st == dr)
{
A[nod + decal] = value[p[path][st - 1]];
return;
}
int mij = st + (dr - st) / 2;
build(st, mij, 2 * nod, path, decal);
build(mij + 1, dr, 2 * nod + 1, path, decal);
A[nod + decal] = max(A[2 * nod + decal], A[2 * nod + 1 + decal]);
}
void query(int st, int dr, int nod, int a, int b, int decal)
{
if(a <= st && dr <= b)
{
qs = max(A[nod + decal], qs);
return;
}
int mij = st + (dr - st) / 2;
if(a <= mij)
{
query(st, mij, 2 * nod, a, b, decal);
}
if(b > mij)
{
query(mij + 1, dr, 2 * nod + 1, a, b, decal);
}
}
void dfs(int nod)
{
u[nod] = 1;
wg[nod] = 1;
int hn = -1, frunza = 1;
for(int i = 0; i < G[nod].size(); i++)
{
int fiu = G[nod][i];
if(u[fiu] == 0)
{
niv[fiu] = 1 + niv[nod];
dfs(fiu);
frunza = 0;
wg[nod] += wg[fiu];
if(hn == -1)
{
hn = fiu;
}else
{
if(wg[fiu] > wg[hn])
{
hn = fiu;
}
}
}
}
if(frunza)
{
np++;
wp[nod] = np;
ps[np] = 1;
p[np].push_back(nod);
return;
}
wp[nod] = wp[hn];
ps[wp[nod]]++;
p[wp[nod]].push_back(nod);
for(int i = 0; i < G[nod].size(); i++)
{
int fiu = G[nod][i];
if(wp[fiu] != wp[nod] && niv[fiu] > niv[nod])
{
pf[wp[fiu]] = nod;
pfniv[wp[fiu]] = niv[nod];
}
}
}
void make_paths()
{
niv[1] = 1;
dfs(1);
for(int i = 1; i <= np; i++)
{
reverse(p[i].begin(), p[i].end());
}
for(int i = 1; i < np; i++)
{
dcj[i + 1] = 4 * p[i].size() + dcj[i];
build(1, p[i].size(), 1, i, dcj[i]);
}
build(1, p[np].size(), 1, np, dcj[np]);
}
int main()
{
_cin >> n >> m;
for(int i = 1; i <= n; i++)
{
_cin >> value[i];
}
for(int i = 1; i < n; i++)
{
_cin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
make_paths();
for(int i = 1; i <= m; i++)
{
_cin >> op >> x >> y;
if(op == 0)
{
update(1, ps[wp[x]], 1, niv[x] - pfniv[wp[x]], y, dcj[wp[x]]);
}else
{
sol_path = 0;
while(wp[x] != wp[y])
{
if(pfniv[wp[x]] < pfniv[wp[y]])
{
swap(x, y);
}
qs = 0;
query(1, ps[wp[x]], 1, 1, niv[x] - pfniv[wp[x]], dcj[wp[x]]);
x = pf[wp[x]];
sol_path = max(qs, sol_path);
}
if(niv[x] < niv[y])
{
swap(x, y);
}
qs = 0;
query(1, ps[wp[x]], 1, niv[y] - pfniv[wp[y]], niv[x] - pfniv[wp[x]], dcj[wp[x]]);
sol_path = max(qs, sol_path);
_cout << sol_path << "\n";
}
}
return 0;
}