/**
* Worg
*/
#include <cstdio>
#include <vector>
#include <algorithm>
using std::vector;
FILE *fin = freopen("heavypath.in", "r", stdin);
FILE *fout = freopen("heavypath.out", "w", stdout);
const int kMaxN = 1 + 100000;
/*-------- Structures --------*/
struct Chain;
struct Node;
struct Node {
int index, depth, weight, value;
vector<Node* > adj_nodes;
Chain *chain;
};
struct Chain {
Node *father;
vector<Node* > nodes;
vector<int > arbint;
int delay, max_depth;
bool ok;
Chain() {this->ok = false;}
};
/*-------- Input data --------*/
int N, M;
Node graph[kMaxN];
/*-------- Chain data --------*/
/*-------- --------*/
void ReadInput() {
scanf("%d%d", &N, &M);
for(int i = 1; i <= N; i++) {
scanf("%d", &graph[i].value);
graph[i].index = i;
}
for(int i = 2; i <= N; i++) {
int a, b; scanf("%d%d", &a, &b);
graph[a].adj_nodes.push_back(&graph[b]);
graph[b].adj_nodes.push_back(&graph[a]);
}
}
void DFS(Node *node, int depth = 1, int dad = 0) {
node->depth = depth;
node->weight = 1;
Node *son;
int son_weight = 0;
for(Node *nxt : node->adj_nodes) {
if(nxt->index != dad) {
DFS(nxt, depth + 1, node->index);
node->weight += nxt->weight;
if(nxt->weight > son_weight) {
son_weight = nxt->weight;
son = nxt;
}
}
}
if(son_weight == 0) { // Nodul este frunza, deci creem un lant nou
node->chain = new Chain();
} else { // Adaugam nodul curent la lantul celui mai greu fiu din subarbore
node->chain = son->chain;
for(Node *nxt : node->adj_nodes) {
if(nxt->index != dad && nxt->index != son->index) {
nxt->chain->father = node;
}
}
}
// Adaugam nodul la lant
node->chain->nodes.push_back(node);
}
void Update(vector<int > &arbint, int node, int left, int right, int pos, int value) {
arbint[node] = 0;
if(left == right) {
arbint[node] = value;
} else {
int mid = (left + right) >> 1;
int left_son = node << 1;
int right_son = left_son + 1;
if(pos <= mid) {
Update(arbint, left_son, left, mid, pos, value);
} else {
Update(arbint, right_son, mid + 1, right, pos, value);
}
arbint[node] = std::max(arbint[left_son], arbint[right_son]);
}
}
void Query(vector<int > &arbint, int node, int left, int right, int first, int last, int &answer) {
if(first <= left && right <= last) {
answer = std::max(answer, arbint[node]);
} else {
int mid = (left + right) >> 1;
int left_son = node << 1;
int right_son = left_son + 1;
if(first <= mid) {
Query(arbint, left_son, left, mid, first, last, answer);
}
if(mid < last) {
Query(arbint, right_son, mid + 1, right, first, last, answer);
}
}
}
void ConstructArbints() {
for(int i = 1; i <= N; i++) {
Chain *chain = graph[i].chain;
if(!chain->ok) { // Daca nu am construit deja arborele de intervale pentru lantul curent
int space_needed = (int)chain->nodes.size() + 1;
chain->arbint.reserve(space_needed << 2);
chain->ok = true;
// Calculam max_depth si delay. Nodurile sunt introduse in lista de jos in sus
chain->delay = chain->nodes.back()->depth - 1;
chain->max_depth = chain->nodes[0]->depth;
// Construim arborele de intervale
for(Node *node : chain->nodes) {
Update(chain->arbint, 1, 1, chain->max_depth - chain->delay, node->depth - chain->delay, node->value);
}
}
}
}
int GetQueryAnswer(Node *u, Node *v) {
int query_answer = 0;
if(u->chain == v->chain) {
Chain *chain = u->chain;
Query(chain->arbint, 1, 1, chain->max_depth - chain->delay, std::min(u->depth, v->depth) - chain->delay, std::max(u->depth, v->depth) - chain->delay, query_answer);
} else {
int h1 = u->chain->father->depth;
int h2 = v->chain->father->depth;
if(h1 < h2) {
Chain *chain = v->chain;
Query(chain->arbint, 1, 1, chain->max_depth - chain->delay, 1, v->depth - chain->delay, query_answer);
query_answer = std::max(query_answer, GetQueryAnswer(u, chain->father));
} else {
Chain *chain = u->chain;
Query(chain->arbint, 1, 1, chain->max_depth - chain->delay, 1, u->depth - chain->delay, query_answer);
query_answer = std::max(query_answer, GetQueryAnswer(chain->father, v));
}
}
return query_answer;
}
void ProcessOperations() {
for(int i = 1; i <= M; i++) {
int type, x, y; scanf("%d%d%d", &type, &x, &y);
if(type == 0) {
graph[x].value = y;
Chain *chain = graph[x].chain;
Update(chain->arbint, 1, 1, chain->max_depth - chain->delay, graph[x].depth - chain->delay, graph[x].value);
} else {
printf("%d\n", GetQueryAnswer(&graph[x], &graph[y]));
}
}
}
int main() {
ReadInput();
DFS(&graph[1]);
graph[0].depth = 0; graph[1].chain->father = &graph[0];
ConstructArbints();
ProcessOperations();
return 0;
}