#include <fstream>
// #include <iostream>
#include <vector>
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
const int NMAX = 1e5 + 5;
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);
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, m;
int Value[NMAX + 1];
vector<int> G[NMAX + 1];
int H[NMAX + 1];
int Parent[NMAX + 1];
int W[NMAX + 1];
int HeavyEdge[NMAX + 1];
vector<int> Path[NMAX + 1];
int Head[NMAX + 1];
int num_Paths = 1;
int WhatPath[NMAX + 1];
int PosPath[NMAX + 1];
AINT aint_Path[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 InitializePaths()
{
for (int i = 1; i <= NMAX; i++)
Path[i].push_back(0);
}
void CreatePaths(int Node, int Curent_Head, int Dad)
{
Head[Node] = Curent_Head;
Path[num_Paths].push_back(Value[Node]);
WhatPath[Node] = num_Paths;
PosPath[Node] = Path[num_Paths].size() - 1;
if (HeavyEdge[Node])
CreatePaths(HeavyEdge[Node], Curent_Head, Node);
for (int Child : G[Node])
if (Child != Dad && Child != HeavyEdge[Node])
{
num_Paths++;
CreatePaths(Child, Child, Node);
}
}
int Query(int x, int y)
{
int max_value = 0;
while (Head[x] != Head[y])
{
if (H[Head[x]] > H[Head[y]])
swap(x, y);
int max_value_path = aint_Path[WhatPath[Head[y]]].Query(PosPath[Head[y]], PosPath[y]);
max_value = max(max_value, max_value_path);
y = Parent[Head[y]];
}
if (H[x] > H[y])
swap(x, y);
int max_value_path = aint_Path[WhatPath[y]].Query(PosPath[x], PosPath[y]);
max_value = max(max_value, max_value_path);
return max_value;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
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);
InitializePaths();
CreatePaths(1, 1, 0);
for (int i = 1; i <= num_Paths; i++)
aint_Path[i].Build(Path[i]);
while (m--)
{
int tip, x, y;
cin >> tip >> x >> y;
if (tip == 0)
aint_Path[WhatPath[x]].Update(PosPath[x], y);
else
cout << Query(x, y) << '\n';
}
return 0;
}