#include <bits/stdc++.h>
using namespace std;
const int INF = 2e9;
const int NMAX = 1e5;
const int LOG_MAX = 17;
const int ROOT = 1;
const int PARENT = 0;
const int NULL_COST = 0;
class InParser {
private:
FILE *fin;
char *buff;
int sp;
char read_ch() {
++sp;
if (sp == 4096) {
sp = 0;
fread(buff, 1, 4096, fin);
}
return buff[sp];
}
public:
InParser(const char* nume) {
fin = fopen(nume, "r");
buff = new char[4096]();
sp = 4095;
}
InParser& operator >> (int &n) {
char c;
while (!isdigit(c = read_ch()) && c != '-');
int sgn = 1;
if (c == '-') {
n = 0;
sgn = -1;
} else {
n = c - '0';
}
while (isdigit(c = read_ch())) {
n = 10 * n + c - '0';
}
n *= sgn;
return *this;
}
InParser& operator >> (long long &n) {
char c;
n = 0;
while (!isdigit(c = read_ch()) && c != '-');
long long sgn = 1;
if (c == '-') {
n = 0;
sgn = -1;
} else {
n = c - '0';
}
while (isdigit(c = read_ch())) {
n = 10 * n + c - '0';
}
n *= sgn;
return *this;
}
};
InParser in ( "heavypath.in" );
ofstream out ( "heavypath.out" );
struct define_edge {
int from, to;
///int cost;
}; vector<define_edge> tree[1 + NMAX];
int father[1 + NMAX], instant_cost[1 + NMAX];
int depth[1 + NMAX], size_of[1 + NMAX];
int n, q;
void dfs ( int p, int root ) {
depth[root] = depth[p] + 1;
father[root] = p;
for ( auto edge : tree[root] ) {
int child = edge.to;
if ( child != p )
dfs ( root, child );
}
size_of[root] = 1;
for ( auto edge : tree[root] ) {
int child = edge.to;
if ( child != p )
size_of[root] += size_of[child];
}
}
int parent[1 + LOG_MAX][1 + NMAX];
class Lowest_Common_Ancestor {
public :
void init ();
int query ( int u, int v );
} LCA;
void Lowest_Common_Ancestor :: init () {
for ( int node = 1; node <= n; node ++ )
parent[0][node] = father[node];
for ( int pwr = 1; (1 << pwr) <= n; pwr ++ )
for ( int node = 1; node <= n; node ++ )
parent[pwr][node] = parent[pwr - 1][parent[pwr - 1][node]];
}
int Lowest_Common_Ancestor :: query ( int u, int v ) {
if ( depth[u] < depth[v] )
swap ( u, v );
for ( int pwr = LOG_MAX; pwr >= 0; pwr -- )
if ( depth[parent[pwr][u]] >= depth[v] )
u = parent[pwr][u];
for ( int pwr = LOG_MAX; pwr >= 0; pwr -- )
if ( parent[pwr][u] != parent[pwr][v] ) {
u = parent[pwr][u];
v = parent[pwr][v];
}
if ( u == v )
return u;
return father[u];
}
int sgtree[1 + 4 * NMAX];
class SegTree {
public :
void update ( int node, int left, int right, int pos, int new_value );
int query ( int node, int left, int right, int qleft, int qright );
static inline int merge__ ( int first, int second );
} ST;
int SegTree :: merge__ ( int first, int second ) {
return max ( first, second );
}
void SegTree :: update ( int node, int left, int right, int pos, int new_value ) {
if ( left == right )
sgtree[node] = new_value;
else {
int mid = left + (right - left) / 2;
if ( pos <= mid )
update ( node * 2, left, mid, pos, new_value );
else
update ( node * 2 + 1, mid + 1, right, pos, new_value );
sgtree[node] = merge__ (sgtree[node * 2], sgtree[node * 2 + 1]);
}
}
int SegTree :: query ( int node, int left, int right, int qleft, int qright ) {
if ( qleft <= left && right <= qright )
return sgtree[node];
int mid = left + (right - left) / 2;
int answer = -INF;
if ( qleft <= mid )
answer = merge__ ( answer, query (node * 2, left, mid, qleft, qright) );
if ( mid + 1 <= qright )
answer = merge__ ( answer, query (node * 2 + 1, mid + 1, right, qleft, qright) );
return answer;
}
bool heavy[1 + NMAX]; /// muchia node-parinte este heavy
int b[1 + NMAX], e[1 + NMAX]; /// nodul de inceput si sfarsit al path-urilor
int chain_indx[1 + NMAX]; int k = 0; /// in ce path se afla nodul x
int pos[1 + NMAX]; /// pozitia in segtree a nodului x
class Heavy_Light_Decomposition {
public :
void dfs_chain ( int p, int root );
void construct_chain ();
void update ( int node, int new_value );
int query ( int u, int v );
} HLD;
void Heavy_Light_Decomposition :: dfs_chain ( int p, int root ) {
for ( auto edge : tree[root] ) {
int child = edge.to;
if ( child != p ) {
if ( size_of[child] > size_of[root] / 2 )
heavy[child] = true;
else
heavy[child] = false;
dfs_chain ( root, child );
}
}
bool all_light = true;
for ( auto edge : tree[root] ) {
int child = edge.to;
if ( child != p && heavy[child] == true )
all_light = false;
}
if ( all_light == true )
b[++ k] = root;
}
void Heavy_Light_Decomposition :: construct_chain () {
int curr_pos = 0;
for ( int indx = 1; indx <= k; indx ++ ) {
int node = b[indx]; chain_indx[node] = indx;
pos[node] = ++ curr_pos;
while ( heavy[node] == true ) {
node = father[node];
chain_indx[node] = indx;
pos[node] = ++ curr_pos;
}
e[indx] = node;
}
}
void Heavy_Light_Decomposition :: update ( int node, int new_value ) {
ST.update ( 1, 1, n, pos[node], new_value );
}
int Heavy_Light_Decomposition :: query ( int u, int v ) {
int answer = -INF;
int bridge = LCA.query ( u, v );
///cout << bridge << "\n";
int start = u;
for ( int step = 0; step < 2; step ++, start = v ) {
int node = start;
while ( chain_indx[node] != chain_indx[bridge] ) {
answer = max ( answer, ST.query ( 1, 1, n, pos[node], pos[e[chain_indx[node]]] ) );
node = father[e[chain_indx[node]]];
}
answer = max ( answer, ST.query ( 1, 1, n, pos[node], pos[bridge] ) );
}
return answer;
}
int main()
{
in >> n >> q;
for ( int node = 1; node <= n; node ++ )
in >> instant_cost[node];
for ( int indx = 1; indx < n; indx ++ ) {
int u, v; in >> u >> v;
tree[u].push_back ( {u, v, } );
tree[v].push_back ( {v, u} );
}
dfs ( PARENT, ROOT ); LCA.init ();
HLD.dfs_chain ( PARENT, ROOT ); HLD.construct_chain ();
/**cout << k << "\n";
for ( int indx = 1; indx <= n; indx ++ )
cout << b[indx] << " " << e[indx] << "\n";**/
for ( int node = 1; node <= n; node ++ )
HLD.update ( node, instant_cost[node] );
for ( int indx = 1; indx <= q; indx ++ ) {
int task; in >> task;
if ( task == 0 ) {
int node, new_value; in >> node >> new_value;
HLD.update ( node, new_value );
}
else {
int u, v; in >> u >> v;
out << HLD.query ( u, v ) << "\n";
}
}
return 0;
}