#include <bits/stdc++.h>
#define MaxN 100001
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
/* ==================== */
int N,T;
int Val[MaxN];
vector<int> G[MaxN];
/* ==================== */
vector<int> Path[MaxN];
int Parent[MaxN];
int whatPath[MaxN],patchN=0;
int PathDim[MaxN];
int PathPosition[MaxN];
int PathDepth[MaxN];
int whatPos[MaxN];
int subtreeNodes[MaxN];
int Depth[MaxN];
bitset<MaxN> Visited;
/* ==================== */
int Arbint[4*MaxN];
/* ==================== */
void read_data()
{
f>>N>>T;
for(int i=1;i<=N;i++) f>>Val[i];
for(int i=1;i<N;i++)
{
int x,y;
f>>x>>y;
G[x].emplace_back(y);
G[y].emplace_back(x);
}
}
void DFS(int node)
{
Visited[node]=1;
subtreeNodes[node]=1;
int isLeaf=1,heavyNode=-1;
for(auto it:G[node])
if(Visited[it]==0)
{
isLeaf=false;
Depth[it] = Depth[node] + 1;
DFS(it);
subtreeNodes[node]+=subtreeNodes[it];
if(heavyNode == -1) heavyNode = it;
else if(subtreeNodes[heavyNode] < subtreeNodes[it]) heavyNode=it;
}
if(isLeaf)
{
whatPath[node] = ++patchN;
PathDim[patchN]=1;
Path[patchN].push_back(node);
return;
}
whatPath[node] =whatPath[heavyNode];
PathDim[whatPath[node]]++;
Path[whatPath[node]].push_back(node);
for(auto it:G[node])
{
if(it==heavyNode || Depth[it]<Depth[node]) continue;
Parent[whatPath[it]]=node;
PathDepth[whatPath[it]]=Depth[node];
}
}
void Build(int node, int left, int right, int lastUsedPosition, int patchIndex)
{
if(left == right)
{
Arbint[node + lastUsedPosition] =Val[ Path[patchIndex][left - 1] ];
return;
}
int mid = (left + right) / 2;
Build(node * 2 , left , mid , lastUsedPosition, patchIndex);
Build(node * 2 + 1, mid+1, right, lastUsedPosition, patchIndex);
Arbint[node + lastUsedPosition] = max(Arbint[node * 2 + lastUsedPosition], Arbint[node * 2 + 1 + lastUsedPosition]);
}
void Update(int node, int left, int right, int poz, int val, int lastUsedPosition)
{
if(left == right)
{
Arbint[node + lastUsedPosition] = val;
return;
}
int mid = (left + right) / 2;
if(poz<=mid) Update(node * 2 , left , mid , poz, val, lastUsedPosition);
else Update(node * 2 + 1, mid+1, right, poz, val, lastUsedPosition);
Arbint[node + lastUsedPosition] = max(Arbint[node * 2 + lastUsedPosition], Arbint[node * 2 + 1 + lastUsedPosition]);
}
int Query(int node, int left, int right, int qleft, int qright, int lastUsedPosition)
{
if(qleft <= left && right <= qright)
return Arbint[node + lastUsedPosition];
int mid=(left + right)/2, rez = 0;
if(qleft <= mid) rez = max(rez, Query(node * 2 , left , mid , qleft, qright, lastUsedPosition) );
if(mid < qright) rez = max(rez, Query(node * 2 + 1, mid + 1, right, qleft, qright, lastUsedPosition) );
return rez;
}
void computePaths()
{
Depth[1] = 1;
DFS(1);
for(int i = 1; i <= patchN; ++i)
{
reverse(Path[i].begin(), Path[i].end());
if(i>1) PathPosition[i] = PathPosition[i-1] + PathDim[i-1] * 4;
Build(1, 1,PathDim[i],PathPosition[i],i);
}
}
int hQuery(int x,int y)
{
int Answer = 0;
while(1)
{
if(whatPath[x] == whatPath[y])
{
if(Depth[x] > Depth[y]) swap(x, y);
Answer= max(Answer, Query(1, 1,PathDim[whatPath[x]],Depth[x] - PathDepth[whatPath[x]],Depth[y] - PathDepth[whatPath[y]], PathPosition[whatPath[x]] ));
break;
}
if(PathDepth[whatPath[x]] < PathDepth[whatPath[y]]) swap(x, y);
Answer=max(Answer, Query(1, 1,PathDim[whatPath[x]], 1,Depth[x] - PathDepth[whatPath[x]], PathPosition[whatPath[x]]) );
x = Parent[whatPath[x]];
}
g<<Answer<<'\n';
}
void solve()
{
while(T--)
{
int type,x,y;
f>>type>>x>>y;
if(type==0) Update(1, 1, PathDim[whatPath[x]], Depth[x] - PathDepth[whatPath[x]], y, PathPosition[whatPath[x]]);
else hQuery(x,y);
}
}
int main()
{
read_data();
computePaths();
solve();
}