#include <bits/stdc++.h>
using namespace std;
const int INF = 2100000000;
int val[100005];
vector<int> v[100005];
int depth[100005];
int in[100005], out[100005], t;
int up[18][100005];
int down[100005];
int heavy[100005];
vector<vector<int>> aint;
int len[100005];
int which[100005];
int pos[100005];
int last[100005];
void dfs(int node)
{
in[node] = ++t;
down[node] = 1;
for(auto son : v[node])
if(!depth[son])
{
depth[son] = depth[node] + 1;
dfs(son);
down[node] += down[son];
}
else up[0][node] = son;
out[node] = ++t;
}
void updateAINT(int idx, int st, int dr, int pos, int p, int x)
{
if(st == dr)
aint[idx][pos] = x;
else
{
int mij = (st+dr>>1);
if(p <= mij) updateAINT(idx, st, mij, pos<<1, p, x);
else updateAINT(idx, mij+1, dr, pos<<1|1, p, x);
aint[idx][pos] = max(aint[idx][pos<<1], aint[idx][pos<<1|1]);
}
}
void queryAINT(int idx, int st, int dr, int pos, int a, int b, int &res)
{
if(a <= st && dr <= b)
res = max(res, aint[idx][pos]);
else
{
int mij = (st+dr>>1);
if(a <= mij) queryAINT(idx, st, mij, pos<<1, a, b, res);
if(b > mij) queryAINT(idx, mij+1, dr, pos<<1|1, a, b, res);
}
}
inline bool ascensor(int a, int b)
{
return in[a] <= in[b] && out[b] <= out[a];
}
int lca(int a, int b)
{
if(depth[a] > depth[b]) swap(a, b);
if(ascensor(a, b)) return a;
for(int i=17; i>=0; --i)
if(!ascensor(up[i][a], up[i][b]))
{
a = up[i][a];
b = up[i][b];
}
return up[0][a];
}
void update(int node, int x)
{
val[node] = x;
updateAINT(which[node], 1, len[which[node]], 1, pos[node], x);
}
int query(int a, int b)
{
int res = 0;
while(which[a] != which[b])
{
queryAINT(which[a], 1, len[which[a]], 1, pos[a], len[which[a]], res);
a = up[0][last[which[a]]];
}
queryAINT(which[a], 1, len[which[a]], 1, pos[a], pos[b], res);
return res;
}
signed main()
{
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
ios::sync_with_stdio(false); fin.tie(0); fout.tie(0);
int n, q; fin>>n>>q;
for(int i=1; i<=n; ++i)
{
fin>>val[i];
heavy[i] = -1;
which[i] = -1;
}
for(int i=1; i<n; ++i)
{
int a, b; fin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
depth[1] = 1;
in[0] = 0; out[0] = INF;
dfs(1);
for(int i=1; i<=n; ++i)
for(int j=0; j<v[i].size(); ++j)
if(v[i][j] != up[0][i] && (heavy[i] == -1 || down[v[i][j]] > down[v[i][heavy[i]]]))
heavy[i] = j;
for(int i=2; i<=n; ++i)
{
if(v[i].size() != 1) continue;
which[i] = aint.size();
len[which[i]] = 1;
last[which[i]] = i;
pos[i] = 1;
aint.push_back(vector<int>());
int node = up[0][i];
while(node != 0 && which[v[node][heavy[node]]] == which[i])
{
which[node] = which[i];
pos[node] = pos[v[node][heavy[node]]] + 1;
++len[which[node]];
last[which[node]] = node;
node = up[0][node];
}
aint[which[i]].assign(4 * len[which[i]], 0);
}
for(int i=1; i<18; ++i)
for(int j=1; j<=n; ++j)
up[i][j] = up[i-1][up[i-1][j]];
for(int i=1; i<=n; ++i)
update(i, val[i]);
while(q--)
{
int t, a, b; fin>>t>>a>>b;
if(t == 0)
update(a, b);
else
fout << max(query(a, lca(a, b)), query(b, lca(a, b))) << '\n';
}
return 0;
}