#include <bits/stdc++.h>
#define VI vector<int>
#define VVI vector<VI>
#define PI pair<int,int>
#define PB push_back
using namespace std;
const int N = 1e5 + 9, Inf = 0x3f3f3f3f;
int cost[N],which[N],poz[N],t[N],dep[N],w[N];
int n,m,a,b,op,x,val;
VVI G;
VVI lanturi;
int tree[8*N + 1];
int root[N];
int NEXT_INDEX;
void Dfs(int x,int p)
{
w[x] = 1;
if(G[x].size() == 1 && dep[x] > 0)
{
which[x] = lanturi.size();
poz[x] = 0;
lanturi.PB(VI(1,x));
return;
}
int maxz = -1;
int nod = -1;
for(auto y : G[x])
{
if(y == p)continue;
t[y] = x;
dep[y] = dep[x] + 1;
Dfs(y, x);
w[x] += w[y];
if(w[y] > maxz)
{
maxz = w[y];
nod = y;
}
}
which[x] = which[nod];
poz[x] = lanturi[which[nod]].size();
lanturi[which[nod]].PB(x);
}
void build(int offset, int nod, int st, int dr, int idx)
{
if(st == dr)
{
tree[nod + offset] = cost[lanturi[idx][st]];
return;
}
int mij = (st + dr) >> 1;
build(offset, nod<<1, st, mij, idx);
build(offset, nod<<1|1, mij + 1, dr, idx);
tree[nod + offset] = max(tree[(nod<<1) + offset], tree[(nod<<1|1) + offset]);
}
void update(int offset, int nod, int st,int dr,int poz, int val)
{
if(st == dr)
{
tree[nod + offset] = val;
return;
}
int mij = (st + dr)>>1;
if(poz <= mij)
update(offset, nod<<1, st, mij, poz, val);
else
update(offset, nod<<1|1, mij+1, dr, poz, val);
tree[nod + offset] = max(tree[(nod<<1) + offset], tree[(nod<<1|1) + offset]);
}
int query(int offset, int nod, int st,int dr,int a, int b)
{
if(a <= st && dr <= b)
return tree[offset + nod];
int mij = (st + dr)>>1;
if(b <= mij)
return query(offset, nod<<1, st, mij, a, b);
else if(a > mij)
return query(offset, nod<<1|1, mij + 1, dr, a, b);
return max(query(offset, nod<<1, st, mij, a, b), query(offset, nod<<1|1, mij + 1, dr, a, b));
}
void Build()
{
for(size_t i = 0; i < lanturi.size(); ++i)
{
root[i] = NEXT_INDEX;
build(root[i], 1, 0, lanturi[i].size() - 1, i);
NEXT_INDEX += 5 * lanturi[i].size();
}
}
int query(int a,int b)
{
if(a == b)return cost[a];
int res = -Inf;
for(; which[a] != which[b]; b = t[lanturi[which[b]][lanturi[which[b]].size() - 1]])
{
if(dep[lanturi[which[a]][lanturi[which[a]].size()-1]] > dep[lanturi[which[b]][lanturi[which[b]].size()-1]])
swap(a, b);
res = max(res, query(root[which[b]], 1, 0, lanturi[which[b]].size() - 1, poz[b], lanturi[which[b]].size() - 1));
}
if(a == b)return res;
if(dep[a] < dep[b])
swap(a, b);
return max(res, query(root[which[a]], 1, 0, lanturi[which[a]].size() - 1, poz[a], poz[b]));
}
int main()
{
freopen("heavypath.in","r", stdin);
freopen("heavypath.out","w", stdout);
cin>>n>>m;
G = VVI(n+1);
for(int i = 1; i <= n; ++i)
cin>>cost[i];
for(int i = 1; i < n; ++i)
{
cin>>a>>b;
G[a].PB(b);
G[b].PB(a);
}
Dfs(1, 0);
Build();
while(m--)
{
cin>>op;
if(op == 0)
{
cin>>x>>val;
update(root[which[x]], 1, 0, lanturi[which[x]].size() - 1, poz[x], val);
}
else
{
cin>>a>>b;
cout<<query(a,b)<<'\n';
}
}
return 0;
}