#include <bits/stdc++.h>
#define all(x) (x).begin(),(x).end()
using namespace std;
#ifndef DLOCAL
#define cin fin
#define cout fout
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
#endif
using ll = long long;
//#define int ll
#define sz(x) ((int)(x).size())
using pii = pair<int,int>;
using tii = tuple<int,int,int>;
const int nmax = 1e5 + 5, inf = 1e9 + 5;
template<typename Node>
struct AINT {
vector<Node> aint;
int n;
void init(int nlen) {
n = nlen;
aint.resize(n * 4, Node());
}
void upd(int p, Node x, int node, int cl, int cr) {
if(p < cl || cr < p) return;
if(cl == cr) { aint[node] = x; return; }
int mid = cl + cr >> 1;
upd(p, x, 2 * node, cl, mid);
upd(p, x, 2 * node + 1, mid + 1, cr);
aint[node] = aint[2 * node] + aint[2 * node + 1];
return;
}
Node query(int l, int r, int node, int cl, int cr) {
if(r < cl || cr < l) return Node();
if(l <= cl && cr <= r) return aint[node];
int mid = cl + cr >> 1;
return query(l, r, 2 * node, cl, mid) + query(l, r, 2 * node + 1, mid + 1, cr);
}
Node query(int l, int r) {
return query(l, r, 1, 1, n);
}
void upd(int p, Node x) {
upd(p, x, 1, 1, n);
}
};
struct Max {
int val;
Max(int x = -1): val(x) {;}
Max operator + (const Max& x) const {
return Max(max(x.val, val));
}
};
vector<int> g[nmax];
namespace Tree {
int pin[nmax], pout[nmax], inp = 1;
int jump[nmax], p[nmax], d[nmax];
AINT<Max> chains[nmax];
int atrch[nmax], pinch[nmax], fch[nmax];
int ptrch = 0;
int area[nmax];
void initarea(int node, int f) {
pin[node] = inp++;
d[node] = d[f] + 1;
p[node] = f;
jump[node] = f;
if(d[jump[f]] - d[jump[jump[f]]] == d[f] - d[jump[f]])
jump[node] = jump[jump[f]];
//--
area[node] = 1;
for(auto x : g[node]) {
if(x == f) continue;
initarea(x, node);
area[node] += area[x];
}
pout[node] = inp;
return;
}
bool isanc(int f, int node) { return pin[f] <= pin[node] && pout[node] <= pout[f]; }
int lca(int x, int y) {
if(isanc(x, y)) return x;
if(isanc(y, x)) return y;
//cerr << x << ' ' << y << '\n';
while(!isanc(x, y)) {
//cerr << x << ' ' << y << '\n';
if(!isanc(jump[x], y))
x = jump[x];
x = p[x];
}
return x;
}
void initch(int node, int f = -1) {
//cerr << node << ' ' << f << ' ' << sz(g[node]) << '\n';
if(sz(g[node]) == 1 && f != -1) { chains[atrch[node]].init(pinch[node]); return; }
int heavyson = g[node][0] == f? g[node][1] : g[node][0];
for(auto x : g[node]) {
if(x == f) continue;
if(area[x] > area[heavyson])
heavyson = x;
}
pinch[heavyson] = pinch[node] + 1;
atrch[heavyson] = atrch[node];
initch(heavyson, node);
for(auto x : g[node]) {
if(x == f || x == heavyson) continue;
pinch[x] = 1;
atrch[x] = ++ptrch;
fch[ptrch] = node;
initch(x, node);
}
return;
}
Max querychain(int x, int l) {
//cerr << x << ' ' << l << '\t' << atrch[x] << ' ' << pinch[l] << '\n';
if(atrch[x] == atrch[l])
return chains[atrch[x]].query(pinch[l], pinch[x]);
return chains[atrch[x]].query(1, pinch[x]) + querychain(fch[atrch[x]], l);
}
int query(int x, int y) {
int l = lca(x, y);
//cerr << querychain(x, l).val << ' ' << querychain(y, l).val << '\n';
return (querychain(x, l) + querychain(y, l)).val;
}
void upd(int x, int val) {
//cerr << "aa\n";
chains[atrch[x]].upd(pinch[x], val);
//cerr << "paappa\n";
}
}
signed main() {
int n, q;
cin >> n >> q;
vector<int> values(n);
for(auto &x : values) cin >> x;
for(int i = 1, x, y; i < n; i++) {
cin >> x >> y;
g[x].emplace_back(y);
g[y].emplace_back(x);
}
Tree::jump[1] = 1;
Tree::d[1] = 0;
Tree::initarea(1, 1);
Tree::pinch[1] = 1;
Tree::initch(1);
for(int i = 1; i <= n; i++)
Tree::upd(i, values[i - 1]);
for(int i = 0, t, x, y; i < q; i++) {
cin >> t >> x >> y;
//cerr << "papa\n";
if(t == 1)
cout << Tree::query(x, y) << '\n';
else
Tree::upd(x, y);
}
}
/**
Vom spune că toamna a venit... foarte trist -
-- George Bacovia, Scântei galbene
*/