#include <iostream>
#include <vector>
#define MAXN 100000
#define LOG_MAXN 20
using namespace std;
struct node{
int chain, posInChain, parent, heavyChild;
int s, lvl, firstApp, val;
vector <int> neighbours;
};
node tree[MAXN];
vector <int> aint[MAXN];
vector <int> chains[MAXN];
int euler[MAXN * 2];
int eulerSize;
int chainSize;
int rmq[2 * MAXN][LOG_MAXN];
int lg[2 * MAXN + 1];
void precalcLg() {
int i;
for ( i = 2; i <= 2 * MAXN; i++ ) {
lg[i] = lg[i / 2] + 1;
}
}
void dfs1(int pos) {
euler[eulerSize] = pos;
eulerSize++;
tree[pos].firstApp = eulerSize - 1;
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);
euler[eulerSize] = pos;
eulerSize++;
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 buildRmq() {
int i, i2;
precalcLg();
for ( i = 0; i < eulerSize; i++ ) {
rmq[i][0] = euler[i];
}
for ( i2 = 1; (1 << i2) <= eulerSize; i2++ ) {
for ( i = 0; i + (1 << i2) + 1 <= eulerSize; i++ ) {
if ( tree[rmq[i][i2 - 1]].lvl < tree[rmq[i + (1 << (i2 - 1))][i2 - 1]].lvl ) {
rmq[i][i2] = rmq[i][i2- 1];
} else {
rmq[i][i2] = rmq[i + (1 << (i2 - 1))][i2 - 1];
}
}
}
}
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 lca(int a, int b) {
int len;
a = tree[a].firstApp;
b = tree[b].firstApp;
if ( a > b ) {
swap(a, b);
}
len = b - a + 1;
if ( tree[rmq[a][lg[len]]].lvl < tree[rmq[b - (1 << lg[len]) + 1][lg[len]]].lvl ) {
return rmq[a][lg[len]];
}
return rmq[b - (1 << lg[len]) + 1][lg[len]];
}
int queryForChain(int start, int finish) {
int pos, ans;
if ( tree[start].lvl < tree[finish].lvl ) {
swap(start, finish);
}
pos = start;
ans = 0;
while ( tree[pos].chain != tree[finish].chain ) {
ans = max(ans, queryAint(tree[pos].chain, 0, tree[pos].posInChain, 0, chains[tree[pos].chain].size() - 1, 0));
pos = tree[chains[tree[pos].chain][0]].parent;
}
ans = max(ans, queryAint(tree[pos].chain, tree[finish].posInChain, tree[pos].posInChain, 0, chains[tree[pos].chain].size() - 1, 0));
return ans;
}
int mainQuery(int a, int b) {
int upNode;
upNode = lca(a, b);
return max(queryForChain(a, upNode), queryForChain(b, upNode));
}
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);
}
eulerSize = 0;
chainSize = 0;
dfs1(0);
dfs2(0, chainSize);
buildRmq();
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;
}