#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#define MAX_N 100001
using namespace std;
typedef struct node{
int val;
int leftIndex, rightIndex;
struct node *left;
struct node *right;
} NODE;
typedef struct path{
vector<int> nodes;
int parentVal;
NODE *associatedIntervalTree;
} PATH;
vector<PATH> paths;
int whatPath[MAX_N];
int whatPos[MAX_N];
int n,m;
int val[MAX_N];
int visited[MAX_N];
vector<int> adjacencyList[MAX_N];
int depths[MAX_N];
int dfs(int node, int currentDepth){
int isLeaf = 1;
visited[node] = 1;
depths[node] = currentDepth;
vector<int> childPathIndices;
int pathIndexWithMaxNodes;
int maxNodes = -1;
int nrOfNodes = 1;
for (int i=0; i<adjacencyList[node].size(); i++){
int nextNode = adjacencyList[node][i];
if (!visited[nextNode]){
isLeaf = 0;
int nodesNr = dfs(nextNode, currentDepth+1);
nrOfNodes += nodesNr;
int pathIndex = whatPath[nextNode];
childPathIndices.push_back(pathIndex);
if (nodesNr > maxNodes){
maxNodes = nodesNr;
pathIndexWithMaxNodes = pathIndex;
}
}
}
if (isLeaf){
PATH p;
p.nodes.push_back(node);
p.parentVal = -1;
whatPath[node] = paths.size();
paths.push_back(p);
}
else {
whatPath[node] = pathIndexWithMaxNodes;
paths[pathIndexWithMaxNodes].nodes.push_back(node);
for (int i=0; i<childPathIndices.size(); i++){
int pathIndex = childPathIndices[i];
if (pathIndex != whatPath[node]){
PATH currentPath = paths[pathIndex];
currentPath.parentVal = node;
paths[pathIndex] = currentPath;
}
}
}
return nrOfNodes;
}
void makePaths(){
int swapp;
//we need to reverse the nodes order inside the paths and update the index within a path of the nodes
for (int i=0; i<paths.size(); i++){
int pathNodesSize = paths[i].nodes.size();
for (int j=0; j <= ((pathNodesSize-1)/2); j++){
swapp = paths[i].nodes[j];
paths[i].nodes[j] = paths[i].nodes[(pathNodesSize-1 - j)];
paths[i].nodes[(pathNodesSize-1 - j)] = swapp;
whatPos[paths[i].nodes[j]] = j;
whatPos[paths[i].nodes[(pathNodesSize-1 - j)]] = (pathNodesSize-1 - j);
}
}
}
int maxx(int val1, int val2){
if (val1 > val2){
return val1;
} else {
return val2;
}
}
int minn(int val1, int val2){
if (val1 < val2){
return val1;
} else {
return val2;
}
}
NODE * initTree(const vector<int> &nodes, int left, int right){
if (left == right){
NODE *p = (NODE *) malloc(sizeof(NODE));
p->left = NULL;
p->right = NULL;
p->val = val[nodes[left]];
p->leftIndex = left;
p->rightIndex = right;
return p;
}
int mid = (left + right)/2;
NODE *p = (NODE *) malloc(sizeof(NODE));
p->leftIndex = left;
p->rightIndex = right;
p->left = initTree(nodes, left, mid);
p->right = initTree(nodes, mid+1, right);
p->val = maxx(p->left->val, p->right->val);
return p;
}
void initIntervalTrees(){
for (int i=0; i<paths.size(); i++){
PATH currentPath = paths[i];
currentPath.associatedIntervalTree = initTree(currentPath.nodes, 0, currentPath.nodes.size()-1);
paths[i] = currentPath;
}
}
NODE *updateIntervalTree(NODE *p, int pos, int newVal){
if (p->leftIndex == p->rightIndex){
p->val = newVal;
return p;
}
int mid = (p->leftIndex + p->rightIndex)/2;
if (pos <= mid){
p->left = updateIntervalTree(p->left, pos, newVal);
} else {
p->right = updateIntervalTree(p->right, pos, newVal);
}
p->val = maxx(p->left->val, p->right->val);
return p;
}
int intersects(int left1, int right1, int left2, int right2){
int doesntIntersect = (right1< left2) || (right2 < left1);
return !doesntIntersect;
}
int queryIT(NODE *p, int left, int right){
int maxVal = -1;
if (p->leftIndex >= left && p->rightIndex <= right){
return p->val;
}
int mid = (p->leftIndex + p->rightIndex)/2;
if (intersects(p->leftIndex, mid, left, right)){
maxVal = queryIT(p->left, left, right);
}
if (intersects(mid, p->rightIndex, left, right)){
int currentVal = queryIT(p->right, left, right);
maxVal = maxx(currentVal, maxVal);
}
return maxVal;
}
int query(int x, int y){
int swapp;
int maxValue = -1;
int finished = 0;
while (!finished){
if (whatPath[x] == whatPath[y]){
int minIndex = minn(whatPos[x], whatPos[y]);
int maxIndex = maxx(whatPos[x], whatPos[y]);
int currentVal = queryIT(paths[whatPath[x]].associatedIntervalTree, minIndex, maxIndex);
maxValue = maxx(maxValue, currentVal);
finished = 1;
} else {
if (depths[paths[whatPath[x]].parentVal] < depths[paths[whatPath[y]].parentVal]){
swapp = x;
x = y;
y = swapp;
}
int currentVal = queryIT(paths[whatPath[x]].associatedIntervalTree, 0, whatPos[x]);
maxValue = maxx(currentVal, maxValue);
x = paths[whatPath[x]].parentVal;
}
}
return maxValue;
}
void solve(){
int operation,x,y;
while (scanf("%d %d %d", &operation, &x, &y) != EOF){
if (operation == 0){ //operation 0 (update)
PATH path = paths[whatPath[x]];
path.associatedIntervalTree = updateIntervalTree(path.associatedIntervalTree, whatPos[x], y);
val[x] = y;
}
else { //operation 1 (query)
int maxValueOnPath = query(x,y);
printf("%d\n", maxValueOnPath);
}
}
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%d %d", &n, &m);
int currentVal;
for (int i=1; i<=n; i++){
scanf("%d", ¤tVal);
val[i] = currentVal;
}
int nod1, nod2;
for (int i=0; i<n-1; i++){
scanf("%d %d", &nod1, &nod2);
adjacencyList[nod1].push_back(nod2);
adjacencyList[nod2].push_back(nod1);
}
//suppose 1 is the roots
dfs(1, 1);
makePaths();
initIntervalTrees();
solve();
return 0;
}