#include <iostream>
#include <vector>
#define MAXN 100000
#define LOG_MAXN 20
using namespace std;
struct node{
int chain, posInChain, parent, heavyChild;
int s, lvl, val;
vector <int> neighbours;
};
node tree[MAXN];
vector <int> aint[MAXN];
vector <int> chains[MAXN];
int chainSize;
void dfs1(int pos) {
tree[pos].s = 1;
tree[pos].heavyChild = -1;
for ( int v : tree[pos].neighbours ) {
if ( tree[pos].parent != v ) {
tree[v].parent = pos;
tree[v].lvl = tree[pos].lvl + 1;
dfs1(v);
tree[pos].s += tree[v].s;
if ( tree[pos].heavyChild == -1 || tree[tree[pos].heavyChild].s < tree[v].s ) {
tree[pos].heavyChild = v;
}
}
}
}
void dfs2(int pos, int chain) {
chains[chain].push_back(pos);
tree[pos].chain = chain;
tree[pos].posInChain = chains[chain].size() - 1;
for ( int v : tree[pos].neighbours ) {
if ( v != tree[pos].parent ) {
if ( v == tree[pos].heavyChild ) {
dfs2(v, chain);
} else {
chainSize++;
dfs2(v, chainSize);
}
}
}
}
void initialiseAint(int aintPos) {
int s;
s = chains[aintPos].size() * 2;
while ( s-- ) {
aint[aintPos].push_back(0);
}
}
void buildAint(int aintPos, int l, int r, int n) {
if ( l == r ) {
aint[aintPos][n] = tree[chains[aintPos][l]].val;
return;
}
int nSt, nDr, mij;
mij = (l + r) / 2;
nSt = n + 1;
nDr = n + 2 * (mij - l + 1);
buildAint(aintPos, l, mij, nSt);
buildAint(aintPos, mij + 1, r, nDr);
aint[aintPos][n] = max(aint[aintPos][nSt], aint[aintPos][nDr]);
}
int queryAint(int aintPos, int qL, int qR, int l, int r, int n) {
if ( qL <= l && r <= qR ) {
return aint[aintPos][n];
}
int nSt, nDr, mij, ans;
mij = (l + r) / 2;
nSt = n + 1;
nDr = n + 2 * (mij - l + 1);
ans = 0;
if ( qL <= mij ) {
ans = max(ans, queryAint(aintPos, qL, qR, l, mij, nSt));
}
if ( mij < qR ) {
ans = max(ans, queryAint(aintPos, qL, qR, mij + 1, r, nDr));
}
return ans;
}
void updateAint(int aintPos, int pos, int l, int r, int n) {
if ( l == r ) {
aint[aintPos][n] = tree[chains[aintPos][l]].val;
return;
}
int nSt, nDr, mij;
mij = (l + r) / 2;
nSt = n + 1;
nDr = n + 2 * (mij - l + 1);
if ( pos <= mij ) {
updateAint(aintPos, pos, l, mij, nSt);
} else {
updateAint(aintPos, pos, mij + 1, r, nDr);
}
aint[aintPos][n] = max(aint[aintPos][nSt], aint[aintPos][nDr]);
}
int mainQuery(int a, int b) {
int ans;
if ( tree[a].lvl < tree[b].lvl ) {
swap(a, b);
}
ans = 0;
while ( tree[a].chain != tree[b].chain ) {
//printf("%d %d %d %d %d %d\n", a, b, tree[a].chain, tree[b].chain, tree[tree[chains[tree[a].chain][0]].parent].lvl, tree[tree[chains[tree[b].chain][0]].parent].lvl);
if ( tree[tree[chains[tree[a].chain][0]].parent].lvl < tree[tree[chains[tree[b].chain][0]].parent].lvl || a == 0 ) {
swap(a, b);
}
ans = max(ans, queryAint(tree[a].chain, 0, tree[a].posInChain, 0, chains[tree[a].chain].size() - 1, 0));
a = tree[chains[tree[a].chain][0]].parent;
//printf("%d %d %d %d\n", a, b, tree[a].chain, tree[b].chain);
}
if ( tree[a].lvl < tree[b].lvl ) {
swap(a, b);
}
ans = max(ans, queryAint(tree[a].chain, tree[b].posInChain, tree[a].posInChain, 0, chains[tree[a].chain].size() - 1, 0));
return ans;
}
void addEdge(int a, int b) {
tree[a].neighbours.push_back(b);
tree[b].neighbours.push_back(a);
}
int main() {
FILE *fin, *fout;
fin = fopen("heavypath.in", "r");
fout = fopen("heavypath.out", "w");
int n, q, i, t, a, b;
fscanf(fin, "%d%d", &n, &q);
for ( i = 0; i < n; i++ ) {
fscanf(fin, "%d", &tree[i].val);
}
for ( i = 0; i < n - 1; i++ ) {
fscanf(fin, "%d%d", &a, &b);
a--;
b--;
addEdge(a, b);
}
chainSize = 0;
dfs1(0);
dfs2(0, chainSize);
for ( i = 0; i <= chainSize; i++ ) {
initialiseAint(i);
buildAint(i, 0, chains[i].size() - 1, 0);
}
while ( q-- ) {
fscanf(fin, "%d%d%d", &t, &a, &b);
a--;
if ( t ) {
b--;
fprintf(fout, "%d\n", mainQuery(a, b));
} else {
tree[a].val = b;
updateAint(tree[a].chain, tree[a].posInChain, 0, chains[tree[a].chain].size() - 1, 0);
}
}
fclose(fin);
fclose(fout);
return 0;
}