#include <bits/stdc++.h>
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
int n, m, no_of_Streaks;
int v[100005];
int level[100005];
int father[100005];
int sons[100005];
int location_of_Node[100005];
int position_in_Heavy_Path[100005];
vector <int> graph[100005];
vector <int> interval_Tree[100005];
vector <int> heavy_Path[100005];
void buildIntervalTrees(int node, int left, int right, int current_Tree)
{
if ( left == right )
{
interval_Tree[current_Tree][node] = v[heavy_Path[current_Tree][left]];
return;
}
int middle = left+(right-left)/2;
buildIntervalTrees(2*node, left, middle, current_Tree);
buildIntervalTrees(2*node+1, middle+1, right, current_Tree);
interval_Tree[current_Tree][node] = max(interval_Tree[current_Tree][2*node], interval_Tree[current_Tree][2*node+1]);
}
void updateIntervalTree(int node, int left, int right, int position, int value, int current_Tree)
{
if ( left == right )
{
interval_Tree[current_Tree][node] = value;
return;
}
int middle = left+(right-left)/2;
if ( position <= middle )
updateIntervalTree(2*node, left, middle, position, value, current_Tree);
else
updateIntervalTree(2*node+1, middle+1, right, position, value, current_Tree);
interval_Tree[current_Tree][node] = max(interval_Tree[current_Tree][2*node], interval_Tree[current_Tree][2*node+1]);
}
int query(int node, int left, int right, int a, int b, int current_Tree)
{
if ( left >= a && right <= b )
return interval_Tree[current_Tree][node];
int answer_on_Left = 0, answer_on_Right = 0;
int middle = left+(right-left)/2;
if ( a <= middle )
answer_on_Left = query(2*node, left, middle, a, b, current_Tree);
if ( b > middle )
answer_on_Right = query(2*node+1, middle+1, right, a, b, current_Tree);
return max(answer_on_Left, answer_on_Right);
}
int findTheMaximumValue(int first_Node, int second_Node)
{
int a, b, answer = 0;
int location_of_First_Node = location_of_Node[first_Node];
int location_of_Second_Node = location_of_Node[second_Node];
if ( location_of_First_Node == location_of_Second_Node )
{
a = min(position_in_Heavy_Path[first_Node], position_in_Heavy_Path[second_Node]);
b = max(position_in_Heavy_Path[first_Node], position_in_Heavy_Path[second_Node]);
answer = max(answer, query(1, 1, (int)heavy_Path[location_of_First_Node].size()-1, a, b, location_of_First_Node));
}
else
{
int last_of_First_Heavy_Path = (int)heavy_Path[location_of_First_Node].size()-1;
int last_of_Second_Heavy_Path = (int)heavy_Path[location_of_Second_Node].size()-1;
if ( level[heavy_Path[location_of_First_Node][last_of_First_Heavy_Path]] < level[heavy_Path[location_of_Second_Node][last_of_Second_Heavy_Path]] )
{
swap (first_Node, second_Node);
swap (location_of_First_Node, location_of_Second_Node);
swap (last_of_First_Heavy_Path, last_of_Second_Heavy_Path);
}
a = position_in_Heavy_Path[first_Node];
b = (int)heavy_Path[location_of_First_Node].size()-1;
int maximum_in_First_Path = query(1, 1, (int)heavy_Path[location_of_First_Node].size()-1, a, b, location_of_First_Node);
int maximum_in_Second_Path = findTheMaximumValue(father[heavy_Path[location_of_First_Node][last_of_First_Heavy_Path]], second_Node);
answer = max(maximum_in_First_Path, maximum_in_Second_Path);
}
return answer;
}
void buildHeavyPath(int node, int parent)
{
father[node] = parent;
level[node] = level[parent]+1;
sons[node] = 1;
for ( auto x:graph[node] )
{
if ( x == parent)
continue;
buildHeavyPath(x, node);
sons[node] += sons[x];
}
if ( sons[node] == 1 )
{
no_of_Streaks++;
position_in_Heavy_Path[node] = 1;
location_of_Node[node] = no_of_Streaks;
heavy_Path[no_of_Streaks].push_back(0);
heavy_Path[no_of_Streaks].push_back(node);
return;
}
int best_Path = 0;
for ( auto x:graph[node] )
{
if ( x == parent )
continue;
if ( sons[x] > sons[best_Path] )
best_Path = x;
}
location_of_Node[node] = location_of_Node[best_Path];
heavy_Path[location_of_Node[best_Path]].push_back(node);
position_in_Heavy_Path[node] = (int)heavy_Path[location_of_Node[best_Path]].size()-1;
}
void readAndSolveQueries()
{
for ( int i = 1; i <= m; ++i )
{
int t, x, y;
fin>>t>>x>>y;
if ( t == 0 )
updateIntervalTree(1, 1, (int)heavy_Path[location_of_Node[x]].size()-1, position_in_Heavy_Path[x], y, location_of_Node[x]);
else
fout<<findTheMaximumValue(x, y)<<'\n';
}
}
void readTree()
{
fin>>n>>m;
for ( int i = 1; i <= n; ++i )
fin>>v[i];
for ( int i = 1; i < n; ++i )
{
int first_Node, second_Node;
fin>>first_Node>>second_Node;
graph[first_Node].push_back(second_Node);
graph[second_Node].push_back(first_Node);
}
}
int main()
{
readTree();
buildHeavyPath(1, 0);
for ( int i = 1; i <= no_of_Streaks; ++i )
{
int size_of_Tree = (int)heavy_Path[i].size()*4;
interval_Tree[i].resize(size_of_Tree);
buildIntervalTrees(1, 1, heavy_Path[i].size()-1, i);
}
readAndSolveQueries();
}