#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
class InParser {
private:
static const int BUFF_SIZE = 1 << 17;
int cursor;
char buff[BUFF_SIZE];
FILE *in_file;
char get_char() {
if(cursor == BUFF_SIZE) {
fread(buff, sizeof(buff[0]), BUFF_SIZE, in_file);
cursor = 0;
}
return buff[cursor++];
}
public:
InParser(const char *filename) {
in_file = fopen(filename, "r");
cursor = BUFF_SIZE;
}
InParser & operator >> (int &nr) {
char ch = get_char();
while(ch < '0' || ch > '9') ch = get_char();
nr = 0;
while(ch >= '0' && ch <= '9') {
nr = nr * 10 + ch - '0';
ch = get_char();
}
return *this;
}
};
class OutParser {
private:
static const int BUFF_SIZE = 1 << 17;
int cursor;
char buff[BUFF_SIZE];
FILE *out_file;
char put_char(char ch) {
if(cursor == BUFF_SIZE) {
fwrite(buff, sizeof(buff[0]), BUFF_SIZE, out_file);
cursor = 0;
}
buff[cursor++] = ch;
}
public:
OutParser(const char *filename) {
out_file = fopen(filename, "w");
cursor = 0;
}
OutParser & operator << (int nr) {
if(!nr) {
put_char('0');
return *this;
}
int cf[10], nrcf = 0;
while(nr) {
cf[nrcf++] = nr % 10;
nr /= 10;
}
for(int i = nrcf - 1; i >= 0; i--) put_char(cf[i] + '0');
return *this;
}
OutParser & operator << (char ch) {
put_char(ch);
return *this;
}
};
const int NMAX = 100000;
int n, m, aint_poz;
int val[NMAX + 5], h[NMAX + 5], aint[2 * NMAX + 5];
int path_first[NMAX + 5], path_dad[NMAX + 5], path_poz[NMAX + 5];
vector<int> v[NMAX + 5];
int dfs(int nod, int dad) {
int cnt = 1, maxc = 0, heaviest = 0;
h[nod] = h[dad] + 1;
for(int i = 0; i < v[nod].size(); i++)
if(v[nod][i] != dad) {
int crt = dfs(v[nod][i], nod);
if(crt > maxc) {
heaviest = i;
maxc = crt;
}
cnt += crt;
}
if(heaviest) swap(v[nod][0], v[nod][heaviest]);
return cnt;
}
void decomposition(int nod, int dad, bool first) {
aint[aint_poz] = val[nod];
path_poz[nod] = aint_poz++;
path_first[nod] = first ? nod : path_first[dad];
path_dad[nod] = first ? dad : path_dad[dad];
for(int i = 0; i < v[nod].size(); i++)
if(v[nod][i] != dad) decomposition(v[nod][i], nod, i);
}
void build() {
for(int i = n - 1; i; i--)
aint[i] = max(aint[i << 1], aint[i << 1 | 1]);
}
void update(int nod, int val) {
aint[path_poz[nod]] = val;
for(int poz = path_poz[nod] >> 1; poz; poz >>= 1)
aint[poz] = max(aint[poz << 1], aint[poz << 1 | 1]);
}
int query(int nod1, int nod2) {
int ans = 0;
if(path_poz[nod1] > path_poz[nod2]) swap(nod1, nod2);
for(int st = path_poz[nod1], dr = path_poz[nod2]; st <= dr; st >>= 1, dr >>= 1) {
if(st & 1)
ans = max(ans, aint[st++]);
if(!(dr & 1))
ans = max(ans, aint[dr--]);
}
return ans;
}
int qquery(int nod1, int nod2) {
int ans = 0;
while(path_first[nod1] != path_first[nod2]) {
if(h[path_first[nod1]] < h[path_first[nod2]]) swap(nod1, nod2);
ans = max(ans, query(path_first[nod1], nod1));
nod1 = path_dad[nod1];
}
ans = max(ans, query(nod1, nod2));
return ans;
}
int main() {
InParser in("heavypath.in");
OutParser out("heavypath.out");
int t, a, b;
in >> n >> m;
for(int i = 1; i <= n; i++) in >> val[i];
for(int i = 1; i < n; i++) {
in >> a >> b;
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1, 0);
aint_poz = n;
decomposition(1, 0, true);
build();
while(m--) {
in >> t >> a >> b;
if(t)
out << qquery(a, b) << '\n';
else
update(a, b);
}
return 0;
}