#include <fstream>
#include <vector>
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
const int NMAX = 1e5;
const int LOGMAX = 20;
class AINT
{
private:
int n = 0;
vector<int> aint;
void Build(int node, int left, int right, vector<int>& a)
{
if (left == right)
aint[node] = a[left];
else
{
int mid = (left + right) / 2;
Build(node * 2, left, mid, a);
Build(node * 2 + 1, mid + 1, right, a);
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
}
void Update(int node, int left, int right, int pos, int value)
{
if (left == right)
aint[node] = value;
else
{
int mid = (left + right) / 2;
if (pos <= mid)
Update(node * 2, left, mid, pos, value);
else
Update(node * 2 + 1, mid + 1, right, pos, value);
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
}
int Query(int node, int left, int right, int Qleft, int Qright)
{
if (left >= Qleft && right <= Qright)
return aint[node];
int mid = (left + right) / 2;
if (mid >= Qright)
return Query(node * 2, left, mid, Qleft, Qright);
if (mid + 1 <= Qleft)
return Query(node * 2 + 1, mid + 1, right, Qleft, Qright);
int LeftNode = Query(node * 2, left, mid, Qleft, Qright);
int RightNode = Query(node * 2 + 1, mid + 1, right, Qleft, Qright);
return max(LeftNode, RightNode);
}
public:
void Build(vector<int>& a)
{
n = a.size() - 1;
aint.resize(4 * n + 1);
Build(1, 1, n, a);
}
void Update(int pos, int value)
{
Update(1, 1, n, pos, value);
}
int Query(int Qleft, int Qright)
{
return Query(1, 1, n, Qleft, Qright);
}
};
int n, Q;
vector<int> G[NMAX + 1];
int Value[NMAX + 1];
int W[NMAX + 1];
int HeavyEdge[NMAX + 1];
int Head[NMAX + 1];
vector<int> Paths[NMAX + 1];
int PathIndex[NMAX + 1];
int Paths_Index = 1;
int H[NMAX + 1];
int Pos[NMAX + 1];
int Parent[NMAX + 1];
AINT aint_Paths[NMAX + 1];
void DFS(int Node, int Dad)
{
H[Node] = H[Dad] + 1;
Parent[Node] = Dad;
int max_W = 0;
for (int Child : G[Node])
if (Child != Dad)
{
DFS(Child, Node);
if (W[Child] > max_W)
{
max_W = W[Child];
HeavyEdge[Node] = Child;
}
W[Node] += W[Child];
}
W[Node]++;
}
void CreatePaths(int Curent_Head, int Node, int Dad)
{
Head[Node] = Curent_Head;
Paths[Paths_Index].push_back(Value[Node]);
PathIndex[Node] = Paths_Index;
Pos[Node] = Paths[Paths_Index].size() - 1;
if (HeavyEdge[Node])
CreatePaths(Curent_Head, HeavyEdge[Node], Node);
for (int Child : G[Node])
if (Child != Dad && HeavyEdge[Node] != Child)
{
Paths_Index++;
CreatePaths(Child, Child, Node);
}
}
int Query(int x, int y)
{
int max_ans = 0;
while (Head[x] != Head[y])
{
if (H[Head[x]] > H[Head[y]])
swap(x, y);
int path_max = aint_Paths[PathIndex[Head[y]]].Query(Pos[Head[y]], Pos[y]);
max_ans = max(max_ans, path_max);
y = Parent[Head[y]];
}
if (H[x] > H[y])
swap(x, y);
int path_max = aint_Paths[PathIndex[x]].Query(Pos[x], Pos[y]);
max_ans = max(max_ans, path_max);
return max_ans;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> Q;
for (int i = 1; i <= n; i++)
cin >> Value[i];
for (int i = 1; i <= n - 1; i++)
{
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
DFS(1, 0);
for (int i = 1; i <= NMAX; i++)
Paths[i].push_back(0);
CreatePaths(1, 1, 0);
for (int i = 1; i <= Paths_Index; i++)
aint_Paths[i].Build(Paths[i]);
while (Q--)
{
int tip, x, y;
cin >> tip >> x >> y;
if (tip == 0)
{
int Path = PathIndex[x];
aint_Paths[Path].Update(Pos[x], y);
}
else
cout << Query(x, y) << '\n';
}
return 0;
}