#include <fstream>
#include <vector>
#include <cstring>
#define root 0
using namespace std;
// 3 ore pierdute pe 0 puncte
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int n;
vector<int> tree[100000];
int chainstart[100000];
int chainend[100000];
int atrchain[100000];
int atrstart[100000];
//int sumofchain[100000];
int pin[100000];
int pout[100000];
int st[100000][17];
int outpoz,inpoz;
int values[100000];
class AINT { // rip iterativ
int aint[262144];
public:
void reset() {
memset(aint,0,sizeof(aint));
}
void update(int val, int poz, int node=1, int cl=0, int cr=n) {
if(cl==cr) {
aint[node]=val;
values[cl]=val;
return;
}
int mid=(cl+cr)/2;
if(poz<=mid)
update(val,poz,2*node,cl,mid);
else
update(val,poz,2*node+1,mid+1,cr);
aint[node]=max(aint[2*node],aint[2*node+1]);
}
int query(int l, int r, int node=1, int cl=0, int cr=n) {
if(l>r)
swap(l,r);
//if(node!=0) {
//cout << l << ' ' << r << ' ' << node << ' '<< cl << ' '<< cr <<' '<< aint[node] << endl;
//}
if(l<=cl && cr<=r) {
return aint[node];
}
int mid=(cl+cr)/2,sum=0;
if(l<=mid)
sum=query(l,r,2*node,cl,mid);
if(mid<r)
sum=max(sum,query(l,r,2*node+1,mid+1,cr));
return sum;
}
} aint;
class INITHLD {
int area[100000];
int nchain,pinaint;
public:
void init() {
aint.reset();
inpoz=0;
outpoz=0;
initareanothers(0,0);
for(int step=1; step<17; step++) {
for(int i=0; i<n; i++) {
st[i][step]=st[st[i][step-1]][step-1];
}
}
nchain=-1;
pinaint=0;
chainstart[0]=0;
initchain(0,0,0);
}
void initareanothers(int node, int father) {
area[node]=1;
st[node][0]=father;
pin[node]=inpoz++;
for(int i=0; i<tree[node].size(); i++) {
if(tree[node][i]!=father) {
initareanothers(tree[node][i],node);
area[node]+=area[tree[node][i]];
}
}
pout[node]=outpoz++;
}
void initchain(int node, int father, int continued) {
//cout << node << ' '<< father <<endl;
if(!continued && nchain>=0)
chainend[nchain]=pinaint-1;
if(!continued) {
nchain++;
chainstart[nchain]=pinaint;
}
atrstart[node]=pinaint;
atrchain[node]=nchain;
aint.update(values[node],pinaint);
pinaint++;
int goodguy=-1;
for(int i=0,child; i<tree[node].size(); i++) {
if(tree[node][i]!=father) {
child=tree[node][i];
if(goodguy==-1 || area[goodguy]<area[child])
goodguy=child;
}
}
if(goodguy!=-1)
initchain(goodguy,node,1);
for(int i=0,child; i<tree[node].size(); i++) {
child=tree[node][i];
if(child!=father&& child!=goodguy)
initchain(child,node,0);
}
}
} initer;
static bool isancestor(int alleged, int father) {
return pin[alleged]>=pin[father] && pout[alleged]<=pout[father];
}
static int lca(int x, int y) {
for(int i=16; i>=0; i--) {
if(!isancestor(y,st[x][i]))
x=st[x][i];
}
return st[x][0];
}
static int getchainsum(int from, int upto) {
if(atrchain[from]==atrchain[upto])
return aint.query(atrstart[upto],atrstart[from]);
int sum=aint.query(chainstart[atrchain[from]],atrstart[from]);
from=st[chainstart[atrchain[from]]][0];
while(atrchain[from]!=atrchain[upto]) {
//cout << from << '\n';
sum=max(sum,aint.query(chainstart[atrchain[from]],from));
from=st[chainstart[atrchain[from]]][0];
}
//cout << "--->" << upto << ' '<< from <<' '<< "+"<< aint.query(atrstart[upto],atrstart[from]) <<"+" << '\n';
sum=max(sum,aint.query(atrstart[upto],atrstart[from]));
return sum;
}
static int query(int x, int y) {
int l=lca(x,y);
//cout << x << ' ' << l << ' '<< y << "___\n";
int a=getchainsum(x,l),b=getchainsum(y,l);
//cout << "___\n" << a << ' ' << b << '\n';
return max(a,b);
}
signed main() {
int q;
cin >> n >> q;
for(int i=0; i<n; i++) {
cin >> values[i];
}
for(int i=1,x,y; i<n; i++) {
cin >> x >> y;
--x,--y;
tree[x].push_back(y);
tree[y].push_back(x);
}
initer.init();
//for(int i=0; i<n; i++)
//cout << atrchain[i] <<' '<< atrstart[i] <<'\n';
//return 0;
for(int i=0,t,x,y; i<q; i++) {
cin >> t >> x >> y;
--x;
if(t==0)
aint.update(y,atrstart[x]);
else
cout << query(x,y-1) << endl;
}
}
/*
*
* 1 2
2 3
2 7
3 4
3 5
3 6
7 8
8 9
1
|
2
/ \
3 7
/ | \ |
4 6 5 8
|
9
*/