#include <bits/stdc++.h>
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
const int LIM = 100'000;
int n, q, t, x, y, z;
int v[LIM + 5], w[LIM + 5], index_norm[LIM + 5], normalizare[LIM + 5];
vector <int> edge[LIM + 5];
int subarbore[LIM + 5], parent[LIM + 5];
inline void calc_subarbore(int crt, int prv){
parent[crt] = prv;
subarbore[crt] = 1;
for(auto nxt : edge[crt])
if(nxt != prv){
calc_subarbore(nxt, crt);
subarbore[crt] += subarbore[nxt];
}
}
inline void continue_lant(int crt, int prv, int lantindex);
int lantcnt, freq_lant[LIM + 5];
vector <int> lant[LIM + 5];
inline void start_lant(int crt, int prv){
lantcnt++;
lant[lantcnt].push_back(crt);
int max_val=0, max_son=-1;
for(auto nxt : edge[crt])
if(nxt != prv){
if(max_val < subarbore[nxt]){
max_val = subarbore[nxt];
max_son = nxt;
}
}
int lantcrt = lantcnt;
if(max_son != -1)
for(auto nxt : edge[crt])
if(nxt != prv){
if(max_son == nxt)
continue_lant(nxt, crt, lantcrt);
else
start_lant(nxt, crt);
}
}
inline void continue_lant(int crt, int prv, int lantindex){
lant[lantindex].push_back(crt);
int max_val=0, max_son=-1;
for(auto nxt : edge[crt])
if(nxt != prv){
if(max_val < subarbore[nxt]){
max_val = subarbore[nxt];
max_son = nxt;
}
}
if(max_son != -1)
for(auto nxt : edge[crt])
if(nxt != prv){
if(max_son == nxt)
continue_lant(nxt, crt, lantindex);
else
start_lant(nxt, crt);
}
}
struct SEGTREE{
int aint[4 * LIM + 5];
inline void build(int nod=1, int st=1, int dr=n){
if(st == dr){
aint[nod] = w[st];
}else{
int md = ((st + dr) >> 1);
build(2*nod , st , md);
build(2*nod+1, md+1, dr);
aint[nod] = max(aint[2*nod], aint[2*nod+1]);
}
}
inline void update(int poz, int val, int nod=1, int st=1, int dr=n){
if(st == dr){
aint[nod] = val;
}else{
int md = ((st + dr) >> 1);
if(poz <= md) update(val, poz, 2*nod , st , md);
if(poz > md) update(val, poz, 2*nod+1, md+1, dr);
aint[nod] = max(aint[2*nod], aint[2*nod+1]);
}
}
inline int query(int qst, int qdr, int nod=1, int st=1, int dr=n){
if(qst <= st && dr <= qdr){
return aint[nod];
}else{
int md = ((st + dr) >> 1), answer = 0;
if(qst <= md) answer = max(answer, query(qst, qdr, 2*nod , st , md));
if(qdr > md) answer = max(answer, query(qst, qdr, 2*nod+1, md+1, dr));
return answer;
}
}
} tree;
int ecnt, euler[2 * LIM + 5], nivel[2 * LIM + 5], level[LIM + 5], first[LIM + 5];
inline void calc_euler(int crt, int prv){
level[crt] = level[prv] + 1;
euler[++ecnt] = crt;
nivel[ecnt] = level[crt];
first[crt] = ecnt;
for(auto nxt : edge[crt])
if(nxt != prv){
calc_euler(nxt, crt);
euler[++ecnt] = crt;
nivel[ecnt] = level[crt];
}
}
int rmq[19][2 * LIM + 5];
inline void calc_rmq(){
for(int j=1; j<=ecnt; j++)
rmq[0][j] = j;
for(int i=1; (1 << i)<=ecnt; i++)
for(int j=1, jj; (jj = j + (1 << (i-1)))<=ecnt; j++)
if(nivel[ rmq[i-1][j] ] < nivel[ rmq[i-1][jj] ])
rmq[i][j] = rmq[i-1][j];
else
rmq[i][j] = rmq[i-1][jj];
}
inline int lca(int nod1, int nod2){
nod1 = first[nod1];
nod2 = first[nod2];
if(nod1 > nod2)
swap(nod1, nod2);
int lg2 = (int)log2(nod2 - nod1 + 1);
nod2 -= (1 << lg2) - 1;
if(nivel[ rmq[lg2][nod1] ] < nivel[ rmq[lg2][nod2] ])
return euler[ rmq[lg2][nod1] ];
else
return euler[ rmq[lg2][nod2] ];
}
inline int query_lant(int nod, int target){
if(freq_lant[nod] == freq_lant[target]){ ///sunt pe acelasi lant
return tree.query(index_norm[target], index_norm[nod]);
}else{
int answer = tree.query(index_norm[ lant[freq_lant[nod]][0] ], index_norm[nod]);
answer = max(answer, query_lant(parent[ lant[freq_lant[nod]][0] ], target));
return answer;
}
}
int main (){
ios_base::sync_with_stdio(false);
fin.tie(nullptr), fout.tie(nullptr);
fin>>n>>q;
for(int i=1; i<=n; i++)
fin>>v[i];
for(int i=1, u, v; i < n; i++){
fin>>u>>v;
edge[u].push_back(v);
edge[v].push_back(u);
}
calc_subarbore(1, 0);
start_lant(1, 0);
int cnt = 0;
for(int i=1; i<=lantcnt; i++)
for(auto nod : lant[i]){
freq_lant[nod] = i;
normalizare[++cnt] = nod;
index_norm[nod] = cnt;
w[cnt] = v[nod];
}
calc_euler(1, 0);
calc_rmq();
tree.build();
while(q--){
fin>>t>>x>>y;
if(t == 0){ ///update
tree.update(x, y);
}else{ ///query
z = lca(x, y);
fout<<max(query_lant(x, z), query_lant(y, z))<<"\n";
}
}
return 0;
}