#include <fstream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int dim = 100005;
int n, opCount;
int v[dim], level[dim], parent[dim], subTree[dim], start[dim];
vector<int> tree[dim];
int pathCount, inPath[dim], parentPath[dim], posInPath[dim];
vector<int> paths[dim];
void dfs(int node, int lvl, int prt) {
level[node] = lvl;
subTree[node] = 1;
parent[node] = prt;
int maxSubTree = 0, maxSon = 0;
for (vector<int>::iterator son = tree[node].begin(); son != tree[node].end(); ++son) {
if (level[*son])
continue;
dfs(*son, lvl + 1, node);
subTree[node] += subTree[*son];
if (subTree[*son] > maxSubTree) {
maxSubTree = subTree[*son];
maxSon = *son;
}
}
if (maxSubTree == 0) {
paths[++pathCount].push_back(node);
inPath[node] = pathCount;
parentPath[pathCount] = parent[node];
}
else {
paths[inPath[maxSon]].push_back(node);
inPath[node] = inPath[maxSon];
parentPath[inPath[node]] = parent[node];
}
}
int aint[4 * dim];
void update(int node, int left, int right, int pos, int val, int decal) {
if (left > right)
return;
if (left == right && left == pos) {
aint[node + decal] = val;
return;
}
int mid = (left + right) / 2;
if (pos <= mid)
update(2 * node, left, mid, pos, val, decal);
else
update(2 * node + 1, mid + 1, right, pos, val, decal);
aint[node + decal] = max(aint[2 * node + decal], aint[2 * node + decal + 1]);
}
int query(int node, int left, int right, int qLeft, int qRight, int decal) {
if (qLeft <= left && right <= qRight)
return aint[node + decal];
int mid = (left + right) / 2, retLeft = 0, retRight = 0;
if (qLeft <= mid)
retLeft = query(2 * node, left, mid, qLeft, qRight, decal);
if (mid < qRight)
retRight = query(2 * node + 1, mid + 1, right, qLeft, qRight, decal);
return max(retLeft, retRight);
}
int main() {
fin >> n >> opCount;
for (int i = 1; i <= n; ++i)
fin >> v[i];
for (int i = 1; i < n; ++i) {
int x, y;
fin >> x >> y;
tree[x].push_back(y);
tree[y].push_back(x);
}
dfs(1, 1, 0);
for (int i = 1; i <= pathCount; ++i) {
start[i] = start[i - 1] + 4 * paths[i - 1].size();
int j = 0, k = paths[i].size() - 1;
for (; j < k; ++j, --k) {
swap(paths[i][j], paths[i][k]);
posInPath[paths[i][j]] = j;
posInPath[paths[i][k]] = k;
}
posInPath[paths[i][j]] = j;
}
for (int i = 1; i <= n; ++i) {
update(1, 0, paths[inPath[i]].size() - 1, posInPath[i], v[i], start[inPath[i]]);
}
while (opCount--) {
int op;
fin >> op;
if (op == 0) {
int node, val;
fin >> node >> val;
update(1, 0, paths[inPath[node]].size() - 1, posInPath[node], val, start[inPath[node]]);
continue;
}
int x, y;
fin >> x >> y;
int sol = 0;
while (true) {
int path1 = inPath[x];
int path2 = inPath[y];
if (path1 == path2) {
int a = posInPath[x];
int b = posInPath[y];
if (a > b) swap(a, b);
sol = max(sol, query(1, 0, paths[path1].size() - 1, a, b, start[path1]));
break;
}
else if (level[parentPath[path1]] > level[parentPath[path2]]) {
int a = posInPath[x];
sol = max(sol, query(1, 0, paths[path1].size() - 1, 0, a, start[path1]));
x = parentPath[path1];
}
else {
int a = posInPath[y];
sol = max(sol, query(1, 0, paths[path2].size() - 1, 0, a, start[path2]));
y = parentPath[path2];
}
}
fout << sol << '\n';
}
return 0;
}
//Trust me, I'm the Doctor!