#include<bits/stdc++.h>
#define nmax 100001
using namespace std;
//matricea arborelui
int n,v[nmax],m;
vector<int> G[nmax];
struct Nod
{
int tata;
int nivel;
int subarb;
int poz;
int chain;
int weight;
};
Nod nodes[nmax];
struct muchie
{
int weight;
int nod_deep;
};
muchie edges[nmax];
//adaugam o muchie, cu ID-ul e, nodurile u si v, cu greutataea w
/*void addEdge(int e,int u,int v)
{
//arborele ca un graf neorientat
tree[u][v]=e;
tree[v][u]=e;
//edges[e-1].weight=w;
}*/
int Arb[4*nmax];
void dfs(int curr,int prev,int lev)
{
int i;
nodes[curr].tata=prev;
nodes[curr].nivel=lev;
nodes[curr].subarb=1;
//pentru toti fiii lui nodului curent
vector<int>::iterator it;
for(it=G[curr].begin();it!=G[curr].end();it++)
//for(i=1;i<=n;i++)
if((*it)!=nodes[curr].tata)
{
dfs((*it),curr,lev+1);
nodes[curr].subarb+=nodes[*it].subarb;
}
}
void hld(int curr_node,int *pos,int *curr_chain,int chain_heads[])
{
if(chain_heads[*curr_chain]==-1)
chain_heads[*curr_chain]=curr_node;
nodes[curr_node].chain=*curr_chain;
nodes[curr_node].poz=++(*pos);
Arb[*pos]=v[curr_node];
//cout<<curr_node<<' '<<(*pos)<<endl;
int special=-1,j;
vector<int>::iterator it;
for(it=G[curr_node].begin();it!=G[curr_node].end();it++)
if((*it)!=nodes[curr_node].tata )
if(special==-1 || nodes[special].subarb<nodes[*it].subarb)
special=(*it);
//cout<<special<<' ';
if(special!=-1)
hld(special,pos,curr_chain,chain_heads);
//pentru fiii normali
for(it=G[curr_node].begin();it!=G[curr_node].end();it++)
if((*it)!=nodes[curr_node].tata && (*it)!=special)
{
//cout<<curr_node<<' '<<*curr_chain<<endl;
++(*curr_chain);
hld((*it),pos,curr_chain,chain_heads);
}
}
//construiesc arborele de intervale pentru Arb
int SegTree[4*nmax];
void ConstrArb(int nod,int st,int dr)
{
int mij=(st+dr)/2;
if(st==dr)
{SegTree[nod]=Arb[st];
return;
}
// else //[st,dr] e inclus in a[b]
// SegTree[nod]=max(SegTree[2*nod],SegTree[2*nod+1]);
else
{
ConstrArb(nod*2,st,mij);
ConstrArb(nod*2+1,mij+1,dr);
SegTree[nod]=max(SegTree[2*nod],SegTree[2*nod+1]);
}
}
//operatia de tip 0
void update(int nod,int st,int dr,int x,int val)
{
//tot pe interval deschis
if(x<st || x>dr);
int mij=(st+dr)/2;
if(st==x && dr==x)
{
SegTree[nod]=val;
return;
}
else
{
if(x<=mij)
update(nod*2,st,mij,x,val);
if(x>mij)
update(nod*2+1,mij+1,dr,x,val);
SegTree[nod]=max(SegTree[2*nod],SegTree[2*nod+1]);
}
}
int LCA(int u,int v)
{
while(u!=v)
{
if(nodes[u].nivel<nodes[v].nivel)
swap(u,v);
u=nodes[u].tata;
}
return v;
}
int LCA_2(int x,int y)
{
while(nodes[x].tata != nodes[y].tata)
if(nodes[x].nivel > nodes[y].nivel)
x = nodes[x].tata;
else
y = nodes[y].tata;
while(x != y)
if(nodes[x].nivel > nodes[y].nivel)
x = nodes[x].tata;
else
y = nodes[y].tata;
return x;
}
//intoarce maximul din [a...b]
int query_1(int nod,int st,int dr,int a,int b)
{
int mij=(st+dr)/2,c,d;
if(a<=st && b>=dr)
return SegTree[nod];
if(dr<a || st>b)
return -1;
return max(query_1(2*nod,st,mij,a,b),query_1(2*nod+1,mij+1,dr,a,b));
}
//functia query la t=1
int crawling(int u,int z,int chain_heads[])
{
int chain_u,chain_z,ans=0,ok=0;
while(!ok )
{
chain_u=nodes[u].chain;
chain_z=nodes[z].chain;
if(chain_u==chain_z)
{ans=max(ans,query_1(1,1,n,min(nodes[u].poz,nodes[z].poz),max(nodes[u].poz,nodes[z].poz)));
ok=1;
}
else
{
ans=max(ans,max( query_1(1,1,n,nodes[chain_heads[chain_u]].poz,nodes[u].poz),query_1(1,1,n,nodes[chain_heads[chain_z]].poz,nodes[z].poz)));
u=nodes[chain_heads[chain_u]].tata;
z=nodes[chain_heads[chain_z]].tata;
if(u==-1) u=1;
if(z==-1) z=1;
if(u==z && u==1)
{
ok=1;
ans=max(ans,v[1]);
}
}
}
return ans;
}
int crawling_2(int u,int z,int chain_heads[])
{
int chain_u,chain_z,ans=0,ok=0;
while(!ok )
{
chain_u=nodes[u].chain;
chain_z=nodes[z].chain;
if(chain_u==chain_z)
{ans=max(ans,query_1(1,1,n,min(nodes[u].poz,nodes[z].poz),max(nodes[u].poz,nodes[z].poz)));
ok=1;
}
else
{
if(nodes[nodes[chain_heads[chain_z]].tata].nivel>nodes[nodes[chain_heads[chain_u]].tata].nivel)
swap(u,z);
ans=max(ans,query_1(1,1,n,nodes[chain_heads[chain_u]].poz,nodes[u].poz));
u=nodes[chain_heads[chain_u]].tata;
//z=nodes[chain_heads[chain_z]].tata;
if(u==-1) u=1;
//if(z==-1) z=1;
}
}
return ans;
}
int max_node(int u,int v,int chain_heads[])
{
int lca=LCA_2(u,v),ans=0;
ans=max(crawling_2(u,lca,chain_heads),crawling_2(v,lca,chain_heads));
return ans;
}
int main()
{
int i,a,b,chain_heads[nmax],t;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
fin>>n>>m;
//memset(tree,-1,sizeof(tree));
for(i=1;i<=n;i++)
fin>>v[i];
memset(chain_heads,-1,sizeof(chain_heads));
for(i=1;i<n;i++)
{
fin>>a>>b;
//addEdge(i,a,b);
G[a].push_back(b);
G[b].push_back(a);
}
int edge_counted=0,curr_chain=1;
dfs(1,-1,0);
//for(i=1;i<=n;i++)
// cout<<nodes[i].subarb<<' ';
hld(1,&edge_counted,&curr_chain,chain_heads);
//cout<<endl;
//for(i=1;i<=pos;i++)
// cout<<Arb[i]<<' ';
int root=1;
ConstrArb(root,1,n);
root=1;
//cout<<SegTree[5];
//cout<<nodes[9].poz;
//cout<<update(root,1,n+1,nodes[3].poz,1);
//for(i=1;i<=curr_chain;i++)
//cout<<chain_heads[i]<<' ';
for(i=1;i<=m;i++)
{
fin>>t>>a>>b;
if(!t)
update(1,1,n,nodes[a].poz,b);
if(t==1)
fout<<max_node(a,b,chain_heads)<<'\n';
}
fin.close();
fout.close();
//cout<<LCA(4,5);
//cout<<query_1(1,1,n+1,3,3);
}