#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
const int nmax = 1e5;
const int maxint = (1 << 30);
int n, nrq, type, x, y, costt[nmax + 2];
vector <int> muchii[nmax + 2];
vector <int> nodepaths[nmax + 2];
int heavypath[nmax + 2], subtreesize[nmax + 2];
int wherenodeidx[nmax + 2], withtag[nmax + 2];
int depth[nmax + 2], father[nmax + 2];
int headpath[nmax + 2];
void dfsbuildhld(int node, int parent){
subtreesize[node] = 1;
depth[node] = 1 + depth[parent];
father[node] = parent;
int heavyson = 0;
for(auto nxt : muchii[node]){
if(nxt != parent){
dfsbuildhld(nxt, node);
subtreesize[node] += subtreesize[nxt];
if(subtreesize[heavyson] < subtreesize[nxt])
heavyson = nxt;
}
}
if(!heavyson){ heavypath[heavyson]++; }
heavypath[node] = heavypath[heavyson];
nodepaths[heavypath[node]].push_back(node);
return;
}
struct segmenttree{
int tree[4 * nmax + 2], mxx;
void build(int node, int st, int dr){
if(st == dr){
tree[node] = costt[withtag[st]];
}else{
int mij = (st + dr) >> 1;
build((node << 1), st, mij);
build((node << 1), mij + 1, dr);
tree[node] = max(tree[(node << 1)], tree[(node << 1) | 1]);
}
}
void update(int node, int st, int dr, int idx){
if(st == dr){
tree[node] = costt[withtag[st]];
}else{
int mij = (st + dr) >> 1;
if(idx <= mij) update((node << 1), st, mij, idx);
if(mij < idx) update((node << 1) | 1, mij + 1, dr, idx);
tree[node] = max(tree[(node << 1)], tree[(node << 1) | 1]);
}
}
int query(int node, int st, int dr, int lf, int rg){
if(lf <= st && dr <= rg){
return tree[node];
}else{
int mij = (st + dr) >> 1, maxival = 0;
if(lf <= mij) maxival = max(maxival, query((node << 1), st, mij, lf, rg));
if(mij < rg) maxival = max(maxival, query((node << 1) | 1, mij + 1, dr, lf, rg));
return maxival;
}
}
} myaint;
int hldquery(int a, int b){
int maxpath = 0;
for(; a != b; ){
if(depth[a] < depth[b])
swap(a, b);
maxpath = max(maxpath, costt[a]);
a = father[a];
}
maxpath = max(maxpath, costt[a]);
return maxpath;
/**int maxpath = 0;
for(; headpath[a] != headpath[b]; ){
if(depth[headpath[a]] < depth[headpath[b]]){
swap(a, b);
}
maxpath = max(maxpath, myaint.query(1, 1, n, wherenodeidx[headpath[a]], wherenodeidx[a]));
a = father[headpath[a]];
}
if(wherenodeidx[a] > wherenodeidx[b]){ swap(a, b); }
maxpath = max(maxpath, myaint.query(1, 1, n, wherenodeidx[a], wherenodeidx[b]));
return maxpath;**/
}
int main(){
in.tie(NULL) -> sync_with_stdio(false); out.tie(NULL);
in>>n>>nrq;
for(int i = 1; i <= n; i++){
in>>costt[i];
}
for(int i = 1; i <= n - 1; i++){
in>>x>>y;
muchii[x].push_back(y);
muchii[y].push_back(x);
}
dfsbuildhld(1, 0);
for(int it = 1; it <= heavypath[0]; it++){
reverse(nodepaths[it].begin(), nodepaths[it].end());
for(auto f : nodepaths[it]){
wherenodeidx[f] = (++wherenodeidx[0]);
withtag[wherenodeidx[0]] = f;
headpath[f] = nodepaths[it][0];
}
///out<<"Path: "<<it<<" -> ";
///for(auto f : nodepaths[it])
/// out<<f<<" "; out<<"\n";
}
myaint.build(1, 1, n); ///build base costs
for(int itq = 1; itq <= nrq; itq++){
in>>type>>x>>y;
if(type == 0){
costt[x] = y;
myaint.update(1, 1, n, wherenodeidx[x]);
}else{
out<<hldquery(x, y)<<"\n";
}
}
return 0;
}