#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <bitset>
#include <deque>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#if __cplusplus > 199711L
#include <unordered_map>
#include <unordered_set>
#endif
#include <cstdio>
#include <ctime>
#include <cmath>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long int64;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int NMAX = 100010, inf = 0x3f3f3f3f;
int N, M, nr_l;
int value[NMAX], l[NMAX], lLVL[NMAX], lFATH[NMAX], lSZ[NMAX], lW[NMAX], LVL[NMAX], tree[4 * NMAX], tOffset[NMAX], father[NMAX];
vector<int> G[NMAX], P[NMAX];
bool visited[NMAX];
void DF(const int node)
{
int it, lN = -1, _node;
visited[node] = true;
for(it = 0; it < (int)G[node].size(); ++it)
{
_node = G[node][it];
if (visited[_node]) continue;
LVL[_node] = LVL[node] + 1;
father[_node] = node;
DF(_node);
if (lN == -1 || lW[lN] < lW[_node])
lN = _node;
}
if (lN == -1)
{
l[node] = ++nr_l;
lSZ[nr_l] = 1;
P[nr_l].push_back(node);
return;
}
lW[node] = lW[lN] + 1;
l[node] = l[lN];
++lSZ[l[node]];
P[l[node]].push_back(node);
for (it = 0; it < (int)G[node].size(); ++it)
{
_node = G[node][it];
if (LVL[_node] < LVL[node] || _node == lN) continue;
lFATH[l[_node]] = node;
lLVL[l[_node]] = LVL[node];
}
}
void update(const int node, const int left, const int right, const int pos, const int value, const int offset)
{
if (left == right)
{
tree[node + offset] = value;
return;
}
int div = (left + right) >> 1;
if (pos <= div) update(node * 2, left, div, pos, value, offset);
else update(node * 2 + 1, div + 1, right, pos, value, offset);
tree[node + offset] = max(tree[node * 2 + offset], tree[node * 2 + 1 + offset]);
}
int query(const int node, const int left, const int right, const int qleft, const int qright, const int offset)
{
if (left >= qleft && right <= qright)
return tree[node + offset];
int ret = -inf;
int div = (left + right) >> 1;
if (qleft <= div) ret = max(ret, query(node * 2, left, div, qleft, qright, offset));
if (qright > div) ret = max(ret, query(node * 2 + 1, div + 1, right, qleft, qright, offset));
return ret;
}
int main()
{
int i, j, x, y, op, a, b;
fin >> N >> M;
for (i = 1; i <= N; ++i)
fin >> value[i];
for (i = 1; i <= N - 1; ++i)
{
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
LVL[1] = 1;
DF(1);
for (i = 1; i <= nr_l; ++i)
{
reverse(P[i].begin(), P[i].end());
tOffset[i] = tOffset[i - 1] + lSZ[i - 1] * 4;
for (j = 0; j < lSZ[i]; ++j)
update(1, 1, lSZ[i], j + 1, value[P[i][j]], tOffset[i]);
}
int res;
while(M--)
{
fin >> op >> a >> b;
if (op == 0)
update(1, 1, lSZ[l[a]], LVL[a] - lLVL[l[a]], b, tOffset[l[a]]);
else
{
res = -inf;
while(true)
{
if (l[a] == l[b])
{
if (LVL[a] > LVL[b]) swap(a, b);
res = max(res, query(1, 1, lSZ[l[a]], LVL[a] - lLVL[l[a]], LVL[b] - lLVL[l[a]], tOffset[l[a]]));
break;
}
if (lLVL[l[a]] < lLVL[l[b]]) swap(a, b);
res = max(res, query(1, 1, lSZ[l[a]], 1, LVL[a] - lLVL[l[a]], tOffset[l[a]]));
a = father[a];
}
fout << res << '\n';
}
}
fin.close();
fout.close();
return 0;
}