#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int nmax = 100000 + 10;
const int LOG = 17;
int fc[nmax] , f[nmax] , w[nmax] , lbl[nmax] , whr[nmax] , v[nmax] , d[nmax];
vector < int > g[nmax] , chain[nmax] , aint[nmax];
int n , q , x , y , nrc , i , j , type , iw , p , m , z , res;
int pa[LOG][nmax];
void change(int k , int x , int l , int r , int p , int y)
{
if (l == r)
{
aint[k][x] = y;
return ;
}
int m = (l + r) >> 1;
if (p <= m)
change(k , 2 * x , l , m , p , y);
else change(k , 2 * x + 1 , m + 1 , r , p , y);
aint[k][x] = max(aint[k][2 * x] , aint[k][2 * x + 1]);
}
int query(int k , int x , int l , int r , int lq , int rq)
{
if (r < lq || rq < l) return 0;
if (lq <= l && r <= rq)
return aint[k][x];
int c = (l + r) >> 1;
return max(query(k , 2 * x , l , c , lq , rq) , query(k , 2 * x + 1 , c + 1 , r , lq , rq));
}
void DP()
{
for (int i = 1 ; i <= LOG ; ++i)
for (int j = 1 ; j <= n ; ++j)
pa[i][j] = pa[i - 1][pa[i - 1][j]];
}
int kanc(int n , int k)
{
for (int i = LOG ; i >= 0 ; --i)
if ( (1 << i) <= k)
{
k -= (1 << i);
n = pa[i][n];
}
return n;
}
int lca(int x , int y)
{
// x is deeper than y
if (d[x] < d[y]) swap(x , y);
int q = d[x] - d[y];
x = kanc(x , q);
if (x == y) return x;
//now x is at same level with y
for (int i = LOG ; i >= 0 ; --i)
if (pa[i][x] != pa[i][y])
{
x = pa[i][x];
y = pa[i][y];
}
return pa[0][x];
}
void df(int x , int fa)
{
w[x] = 1;
f[x] = fa;
d[x] = d[fa] + 1;
pa[0][x] = fa;
for (auto j = g[x].begin() ; j != g[x].end() ; ++j)
{
int y = *j;
if (y == fa) continue;
df(y , x);
w[x] += w[y];
}
}
void doChains(int x)
{
int to = 0 , aux = nrc;
if (chain[nrc].empty()) chain[nrc].push_back(0);
lbl[x] = nrc , whr[x] = chain[nrc].size();
chain[nrc].push_back(x);
for (auto j = g[x].begin() ; j != g[x].end() ; ++j)
{
int y = *j;
if (y == f[x]) continue;
if (w[*j] > w[to]) to = *j;
}
if (to)
doChains(to);
else ++nrc;
for (auto j = g[x].begin() ; j != g[x].end() ; ++j)
{
int y = *j;
if (y == f[x] || y == to) continue;
fc[nrc] = aux;
doChains(y);
}
}
void doInit()
{
for (i = 1 ; i < nrc ; ++i)
{
int m = chain[i].size() - 1;
aint[i].resize(3 * m);
for (j = 1 ; j <= m ; ++j)
change(i , 1 , 1 , m , j , v[chain[i][j]]);
}
}
int go(int x , int z)
{
int iw = lbl[x];
int to = whr[x];
int from;
if (lbl[z] == iw)
from = whr[z];
else from = 1;
int m = chain[iw].size() - 1;
int ans = query(iw , 1 , 1 , m , from , to);
if (lbl[z] == lbl[x]) return ans;
int up = chain[iw][1];
return max(go(f[up] , z) , ans);
}
int main()
{
fin >> n >> q;
for (i = 1 ; i <= n ; ++i)
fin >> v[i];
for (i = 1 ; i < n ; ++i)
{
fin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
df(1 , 0);
DP();
nrc = 1;
doChains(1);
doInit();
for (i = 1 ; i <= q ; ++i)
{
fin >> type >> x >> y;
if (type == 0)
{
iw = lbl[x];
p = whr[x];
m = chain[iw].size() - 1;
change(iw , 1 , 1 , m , p , y);
}
else
{
z = lca(x , y);
res = go(x , z);
res = max(res , go(y , z));
fout << res << '\n';
}
}
return 0;
}