#include <bits/stdc++.h>
#define maxN 100001
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int n, tests, mxx;
int value[maxN], subTreeNodes[maxN], level[maxN], dad[maxN], whereInPath[maxN], whichPath[maxN], pathsNo;
vector<int> v[maxN], segmentTree[maxN], path[maxN];
bool visited[maxN];
inline int maxim(int x, int y) {
return x > y ? x : y;
}
void basicDFS(int x, int father = 0) {
dad[x] = father;
visited[x] = 1;
level[x] = level[dad[x]] + 1;
subTreeNodes[x] = 1;
for (int i = 0 ; i < v[x].size() ; ++i)
if (!visited[v[x][i]]) {
basicDFS(v[x][i], x);
subTreeNodes[x] += subTreeNodes[v[x][i]];
}
}
void pathDFS(int x) {
visited[x] = 0;
int nodeToChoose = 0, mx = 0;
for (int i = 0 ; i < v[x].size() ; ++i)
if (visited[v[x][i]]) {
pathDFS(v[x][i]);
if (subTreeNodes[v[x][i]] > mx) {
nodeToChoose = v[x][i];
mx = subTreeNodes[v[x][i]];
}
}
if (nodeToChoose == 0) {
path[++pathsNo].push_back(x);
whereInPath[x] = 0;
whichPath[x] = pathsNo;
}
else {
path[whichPath[nodeToChoose]].push_back(x);
whereInPath[x] = path[whichPath[nodeToChoose]].size() - 1;
whichPath[x] = whichPath[nodeToChoose];
}
}
void buildSegmentTree(int node, int left, int right, int cnt) {
if (left == right) {
segmentTree[cnt][node] = value[path[cnt][left]];
return;
}
int mid = (left+right)>>1;
buildSegmentTree(node*2, left, mid, cnt);
buildSegmentTree(node*2+1, mid+1, right, cnt);
segmentTree[cnt][node] = maxim(segmentTree[cnt][node*2], segmentTree[cnt][node*2+1]);
}
void updateSegmentTree(int node, int left, int right, int val, int pos, int cnt) {
if (left == right) {
segmentTree[cnt][node] = val;
return;
}
int mid = (left+right)>>1;
if (pos <= mid)
updateSegmentTree(node*2, left, mid, val, pos, cnt);
else
updateSegmentTree(node*2+1, mid+1, right, val, pos, cnt);
segmentTree[cnt][node] = maxim(segmentTree[cnt][node*2], segmentTree[cnt][node*2+1]);
}
void querySegmentTree(int node, int left, int right, int a, int b, int cnt) {
if (a <= left && right <= b) {
if (segmentTree[cnt][node] > mxx) mxx = segmentTree[cnt][node];
return;
}
int mid = (left+right)>>1;
if (a <= mid) querySegmentTree(node*2, left, mid, a, b, cnt);
if (mid < b) querySegmentTree(node*2+1, mid+1, right, a, b, cnt);
}
int solveHPD(int x, int y) {
int maxNode = 0;
while (1) {
if (level[dad[path[whichPath[x]].back()]] < level[dad[path[whichPath[y]].back()]])
swap(x,y);
if (whichPath[x] == whichPath[y]) {
int start = min(whereInPath[x], whereInPath[y]);
int finish = maxim(whereInPath[x], whereInPath[y]);
mxx = 0;
querySegmentTree(1, 0, path[whichPath[x]].size()-1, start, finish, whichPath[x]);
return max(maxNode, mxx);
}
mxx = 0;
querySegmentTree(1, 0, path[whichPath[x]].size()-1, whereInPath[x], path[whichPath[x]].size()-1, whichPath[x]);
maxNode = maxim(maxNode, mxx);
x = dad[path[whichPath[x]].back()];
}
}
int main() {
fin >> n >> tests;
for (int i = 1 ; i <= n ; ++i)
fin >> value[i];
for (int x, y, i = 0 ; i < n-1 ; ++i) {
fin >> x >> y;
v[x].push_back(y);
v[y].push_back(x);
}
basicDFS(1);
pathDFS(1);
for (int i = 1 ; i <= pathsNo ; ++i) {
segmentTree[i].resize(4 * path[i].size());
buildSegmentTree(1, 0, path[i].size()-1, i);
}
while (tests--) {
int t, x, y;
fin >> t >> x >> y;
if (!t) {
value[x] = y;
updateSegmentTree(1, 0, path[whichPath[x]].size() - 1, y, whereInPath[x], whichPath[x]);
}
else
fout << solveHPD(x,y) << '\n';
}
fin.close();
fout.close();
// for (int i = 1 ; i <= pathsNo ; ++i) {
// for (int j = 0 ; j < path[i].size() ; ++j)
// cout << path[i][j] << ' ';
// cout << '\n';
// }
return 0;
}