/*
Dumnezeu cu mila, cine-o sti ce punctaj iau eu
cu sursa asta de peste 200 de randuri :D
*/
#include <cstdio>
#include <algorithm>
#include <vector>
const int DIM = 131072;
const int INF = 0x3f3f3f3f;
using namespace std;
struct tree {int lazy, value;};
struct rangeNode {int value, cost;};
int NrRange, NrNodes, K, X, Y, NrQuerys, node1, node2;
int NodeValue[DIM], Level[DIM], Heavy[DIM], WhatRange[DIM];
int PosInRange[DIM], Marked[DIM], FatherRange[DIM];
vector <int> Edges[DIM];
vector <tree> Tree[DIM];
vector <rangeNode> Range[DIM];
void build_tree (int range, int node, int left, int right) {
if (left > right) return;
if (left == right) {
Tree[range][node].value = Range[range][left].cost;
return;
}
int middle = left + (right - left) / 2;
build_tree (range, node * 2, left, middle);
build_tree (range, node * 2 + 1, middle + 1, right);
if (Tree[range][node * 2].value >= Tree[range][node * 2 + 1].value)
Tree[range][node] = Tree[range][node * 2];
else
Tree[range][node] = Tree[range][node * 2 + 1];
return;
}
void update_tree (int range, int node, int left, int right, int start, int finish, int value) {
if (Tree[range][node].lazy != 0) {
Tree[range][node].value += Tree[range][node].lazy;
if (left != right) {
Tree[range][node * 2].lazy += Tree[range][node].lazy;
Tree[range][node * 2 + 1].lazy += Tree[range][node].lazy;
}
Tree[range][node].lazy = 0;
}
if (left > right || left > finish || start > right) return;
if (start <= left && right <= finish) {
Tree[range][node].value += value;
if (left != right) {
Tree[range][node * 2].lazy += value;
Tree[range][node * 2 + 1].lazy += value;
}
return;
}
int middle = left + (right - left) / 2;
update_tree (range, node * 2, left, middle, start, finish, value);
update_tree (range, node * 2 + 1, middle + 1, right, start, finish, value);
if (Tree[range][node * 2].value >= Tree[range][node * 2 + 1].value)
Tree[range][node] = Tree[range][node * 2];
else
Tree[range][node] = Tree[range][node * 2 + 1];
return;
}
tree query_tree (int range, int node, int left, int right, int start, int finish) {
tree value1, value2, value3; value3.value = -INF;
if (Tree[range][node].lazy != 0) {
Tree[range][node].value += Tree[range][node].lazy;
if (left != right) {
Tree[range][node * 2].lazy += Tree[range][node].lazy;
Tree[range][node * 2 + 1].lazy += Tree[range][node].lazy;
}
Tree[range][node].lazy = 0;
}
if (left > right || left > finish || start > right) return value3;
if (start <= left && right <= finish)
return Tree[range][node];
int middle = left + (right - left) / 2;
value1 = query_tree (range, node * 2, left, middle, start, finish);
value2 = query_tree (range, node * 2 + 1, middle + 1, right, start, finish);
if (value1.value >= value2.value)
value3 = value1;
else
value3 = value2;
return value3;
}
void DFS (int node, int level) {
int ok = 0, maxim = 0, NextRange;
Level[node] = level;
Heavy[node] = 1;
Marked[node] = 1;
vector <int> :: iterator it;
for (it = Edges[node].begin(); it != Edges[node].end(); it ++) {
int NextNode = *it;
if (!Marked[NextNode]) {
ok = 1;
DFS (NextNode, level + 1);
if (maxim < Heavy[NextNode]) {
maxim = Heavy[NextNode];
NextRange = WhatRange[NextNode];
}
Heavy[node] += Heavy[NextNode];
}
}
if (ok == 0) {
NrRange ++;
WhatRange[node] = NrRange; rangeNode aux;
aux.value = node; aux.cost = NodeValue[node];
Range[NrRange].push_back(aux);
return;
}
else {
WhatRange[node] = NextRange; rangeNode aux;
aux.value = node; aux.cost = NodeValue[node];
Range[NextRange].push_back(aux);
vector <int> :: iterator it;
for (it = Edges[node].begin(); it != Edges[node].end(); it ++) {
int NextNode = *it;
if (WhatRange[NextNode] != 0 && WhatRange[NextNode] != WhatRange[node])
FatherRange[WhatRange[NextNode]] = node;
}
}
return;
}
int heavy_query (int X, int Y) {
tree answer;
if (WhatRange[X] == WhatRange[Y]) {
if (PosInRange[X] > PosInRange[Y])
swap (X, Y);
answer = query_tree (WhatRange[X], 1, 0, Range[WhatRange[X]].size() - 1, PosInRange[X], PosInRange[Y]);
return answer.value;
} else {
if (Level[FatherRange[WhatRange[X]]] < Level[FatherRange[WhatRange[Y]]])
swap (X, Y);
answer = query_tree (WhatRange[X], 1, 0, Range[WhatRange[X]].size() - 1, 0, PosInRange[X]);
return max (answer.value, heavy_query (FatherRange[WhatRange[X]], Y));
}
return -1;
}
int main () {
freopen ("heavypath.in" ,"r", stdin );
freopen ("heavypath.out","w", stdout);
scanf ("%d %d", &NrNodes, &NrQuerys);
for (int i = 1; i <= NrNodes; i ++)
scanf ("%d", &NodeValue[i]);
for (int i = 1; i < NrNodes; i ++) {
scanf ("%d %d", &node1, &node2);
Edges[node1].push_back(node2);
Edges[node2].push_back(node1);
}
DFS (1, 1);
for (int i = 1; i <= NrRange; i ++) {
reverse (Range[i].begin(), Range[i].end());
Tree[i].resize(Range[i].size() * 4);
for (int j = 0; j < Range[i].size(); j ++)
PosInRange[Range[i][j].value] = j;
build_tree (i, 1, 0, Range[i].size() - 1);
}
for (int i = 1; i <= NrQuerys; i ++) {
scanf ("%d %d %d", &K, &X, &Y);
switch (K) {
case 0: {
update_tree (WhatRange[X], 1, 0, Range[WhatRange[X]].size() - 1, PosInRange[X], PosInRange[X], Y - Range[WhatRange[X]][PosInRange[X]].cost);
Range[WhatRange[X]][PosInRange[X]].cost = Y;
break;
}
case 1: {
printf ("%d\n", heavy_query(X, Y));
break;
}
}
}
return 0;
}