#include <algorithm>
#include <fstream>
using namespace std;
const int NMAX = 100005, INF = 2000000001;
vector<int> G[NMAX];
int values[NMAX];
vector<int> paths[NMAX];
vector<int> aint[NMAX];
int path[NMAX], cntPaths;
int nodePos[NMAX];
int tsize[NMAX];
int pathFather[NMAX], pathLevel[NMAX], pathSize[NMAX];
void dfs(int node, int prev) {
tsize[node] = 1;
int l = -1;
for (int p: G[node]) {
if (p == prev) continue;
dfs(p, node);
tsize[node] += tsize[p];
if (l == -1 || tsize[p] > tsize[l]) {
l = p;
}
}
if (l == -1) {
path[node] = cntPaths++;
} else {
path[node] = path[l];
}
pathSize[path[node]]++;
}
void dfs2(int node, int prev) {
paths[path[node]][nodePos[node] = pathSize[path[node]]++] = node;
for (int p: G[node]) {
if (p == prev) continue;
if (path[p] != path[node]) {
pathFather[path[p]] = node;
pathLevel[path[p]] = pathLevel[path[node]] + 1;
}
dfs2(p, node);
}
}
void build(vector<int>& aint, vector<int>& nodes,
int node, int left, int right) {
if (left == right) {
aint[node] = values[nodes[left]];
} else {
int mid = (left + right) / 2;
build(aint, nodes, 2 * node + 1, left, mid);
build(aint, nodes, 2 * node + 2, mid + 1, right);
aint[node] = max(aint[2 * node + 1], aint[2 * node + 2]);
}
}
void update(vector<int>& aint, int node, int left, int right,
int pos, int val) {
if (left == right) {
aint[node] = val;
} else {
int mid = (left + right) / 2;
if (pos <= mid) update(aint, 2 * node + 1, left, mid, pos, val);
else update(aint, 2 * node + 2, mid + 1, right, pos, val);
aint[node] = max(aint[2 * node + 1], aint[2 * node + 2]);
}
}
int query(vector<int>& aint, int node, int left, int right, int lq, int rq) {
if (lq <= left && right <= rq) {
return aint[node];
} else {
int mid = (left + right) / 2;
int ret = 0;
if (lq <= mid) ret = query(aint, 2 * node + 1, left, mid, lq, rq);
if (rq > mid)
ret = max(ret, query(aint, 2 * node + 2, mid + 1, right, lq, rq));
return ret;
}
}
int main() {
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int n, q;
fin >> n >> q;
for (int i = 1; i <= n; ++i)
fin >> values[i];
for (int i = 1; i < n; ++i) {
int x, y;
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1, 0);
for (int i = 0; i < cntPaths; ++i) {
paths[i] = vector<int>(pathSize[i]);
pathSize[i] = 0;
}
dfs2(1, 0);
for (int i = 0; i < cntPaths; ++i) {
aint[i] = vector<int>(pathSize[i] * 4);
build(aint[i], paths[i], 0, 0, pathSize[i] - 1);
}
while (q-- > 0) {
int type;
fin >> type;
if (type == 0) {
int node, val;
fin >> node >> val;
update(aint[path[node]], 0, 0, pathSize[path[node]] - 1,
nodePos[node], val);
} else {
int x, y;
fin >> x >> y;
int px = path[x], py = path[y];
int ans = 0;
while (px != py) {
if (pathLevel[px] > pathLevel[py]) {
ans = max(ans, query(aint[px], 0, 0, pathSize[px] - 1,
0, nodePos[x]));
x = pathFather[px];
px = path[x];
} else {
ans = max(ans, query(aint[py], 0, 0, pathSize[py] - 1,
0, nodePos[y]));
y = pathFather[py];
py = path[y];
}
}
int pmin = min(nodePos[x], nodePos[y]);
int pmax = max(nodePos[x], nodePos[y]);
ans = max(ans, query(aint[px], 0, 0, pathSize[px] - 1, pmin, pmax));
fout << ans << '\n';
}
}
fin.close();
fout.close();
}