#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int NMAX = 100000;
int parent[NMAX + 1];
int weight[NMAX + 1];
int level[NMAX + 1];
int value[NMAX + 1];
int position[NMAX + 1];
int a[NMAX + 1];
vector <int> graph[NMAX + 1];
struct node
{
int max;
int rightBound;
int leftBound;
node* leftSon;
node* rightSon;
node (int max, int leftBound, int rightBound, node* leftSon, node* rightSon):
max (max), leftBound (leftBound), rightBound (rightBound),
leftSon (leftSon), rightSon (rightSon) {}
};
class intervalTree
{
private:
node* root;
node* buildTree (int* begin, int* end, int leftBound, int rightBound)
{
if (leftBound == rightBound)
return new node (a[leftBound], leftBound, rightBound, NULL, NULL);
else
{
int med = (leftBound + rightBound) >> 1;
node* leftSon = buildTree (begin, begin + med - leftBound + 1,
leftBound, med);
node* rightSon = buildTree (begin + med - leftBound + 1, end,
med + 1, rightBound);
return new node (max (leftSon->max, rightSon->max),
leftBound, rightBound, leftSon, rightSon);
}
}
void update (node* node, int position, int newValue)
{
if (node->leftBound == position && node->rightBound == position)
node->max = newValue;
else if (node->leftBound <= position && node->rightBound >= position)
{
update (node->leftSon, position, newValue);
update (node->rightSon, position, newValue);
node->max = max (node->leftSon->max, node->rightSon->max);
}
}
int query (node* node, int leftBound, int rightBound)
{
if (leftBound <= node->leftBound && node->rightBound <= rightBound)
return node->max;
else
{
int ans = 0;
if (node->leftSon != NULL && node->leftSon->rightBound >= leftBound)
ans = max(ans, query (node->leftSon, leftBound, rightBound));
if (node->rightSon != NULL && node->rightSon->leftBound <= rightBound)
ans = max (ans, query (node->rightSon, leftBound, rightBound));
return ans;
}
}
public:
void build (int length)
{
root = buildTree (a + 1, a + length + 1, 0, length - 1);
}
void update (int position, int newValue)
{
update (root, position, newValue);
}
int query (int left, int right)
{
return query (root, left, right);
}
};
class heavyPath
{
private:
vector <int> path;
intervalTree tree;
bool built;
public:
int parent;
heavyPath (int vertex = 0)
{
built = false;
addVertex (vertex);
}
void build ()
{
if (!built)
{
built = true;
for (int i = 0; i < path.size (); ++i)
a[i] = value[path[i]];
this->tree.build (path.size ());
}
}
void addVertex (int vertex)
{
this->parent = vertex;
this->path.push_back (vertex);
}
void update (int vertex, int value)
{
this->tree.update (position[vertex], value);
}
int query (int vertexLeft, int vertexRight)
{
return this->tree.query (min (position[vertexLeft], position[vertexRight]),
max (position[vertexLeft], position[vertexRight]));
}
int query (int vertexLeft)
{
return query (vertexLeft, parent);
}
};
heavyPath* path[NMAX + 1];
void buildPaths (int vertex)
{
weight[vertex] = 1;
if (graph[vertex].size () > 1 || graph[vertex][0] != parent[vertex])
{
int maxWeight = 0, bestSon, son;
for (int i = 0; i < graph[vertex].size (); ++i)
{
son = graph[vertex][i];
if (son != parent[vertex])
{
parent[son] = vertex;
level[son] = level[vertex] + 1;
buildPaths (son);
weight[vertex] += weight[son];
if (weight[son] > maxWeight)
maxWeight = weight[son], bestSon = son;
}
}
path[vertex] = path[bestSon];
position[vertex] = position[bestSon] + 1;
path[bestSon]->addVertex (vertex);
}else
{
path[vertex] = new heavyPath (vertex);
position[vertex] = 0;
}
}
int solve (int vertex1, int vertex2)
{
int ans = 0;
while (path[vertex1] != path[vertex2])
{
if (level[path[vertex1]->parent] < level[path[vertex2]->parent])
swap (vertex1, vertex2);
ans = max (ans, path[vertex1]->query (vertex1));
vertex1 = parent[path[vertex1]->parent];
}
ans = max (ans, path[vertex1]->query (vertex1, vertex2));
return ans;
}
int main ()
{
freopen ("heavypath.in", "r", stdin);
freopen ("heavypath.out", "w", stdout);
int n, m, type, x, y;
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf ("%d", &value[i]);
for (int i = 1; i < n; ++i)
{
scanf ("%d%d", &x, &y);
graph[x].push_back (y);
graph[y].push_back (x);
}
level[1] = 1;
buildPaths (1);
for (int i = 1; i <= n; ++i)
path[i]->build ();
for(int i = 1; i <= m; ++i)
{
scanf ("%d%d%d", &type, &x, &y);
if (type == 0)
path[x]->update (x, y);
else if (type == 1)
printf ("%d\n", solve (x, y));
}
return 0;
}