#include<bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#define int long long
using namespace std;
const int N=5e5+10;
int head[N],vct[N],nxt[N],w[N],w_new[N],fa[N],dep[N],siz[N],top[N],son[N],dfn[N],idx,tot;
void add(int x,int y){
vct[++idx]=y;
nxt[idx]=head[x];head[x]=idx;
}
void dfs(int u,int f){
siz[u]=1;
for(int i=head[u];i;i=nxt[i]){
int v=vct[i];
if(v==f)continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp;
dfn[u]=++tot;
w_new[tot]=w[u];
if(!son[u])return;
dfs2(son[u],tp);
for(int i=head[u];i;i=nxt[i]){
int v=vct[i];
if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
}
struct node{
int sum,pre,suf,ans,l,r,tag;
}t[4*N];
void pushup(node &p,node ls,node rs){
p.sum=ls.sum+rs.sum;
p.pre=max(ls.pre,ls.sum+rs.pre);
p.suf=max(rs.suf,rs.sum+ls.suf);
p.ans=max(max(ls.ans,rs.ans),ls.suf+rs.pre);
}
void pushdown(int p){
if(t[p].tag!=INT_MIN){
t[2*p].sum=t[p].tag*(t[2*p].r-t[2*p].l+1);
t[2*p+1].sum=t[p].tag*(t[2*p+1].r-t[2*p+1].l+1);
t[2*p].pre=t[2*p].suf=t[2*p].ans=max(t[2*p].sum,0LL);
t[2*p+1].pre=t[2*p+1].suf=t[2*p+1].ans=max(t[2*p+1].sum,0LL);
t[2*p].tag=t[2*p+1].tag=t[p].tag;
t[p].tag=INT_MIN;
}
}
int a[N];
void build(int L,int R,int p){
t[p].l=L,t[p].r=R;t[p].tag=INT_MIN;
if(L==R){
t[p].sum=w_new[L];
t[p].pre=t[p].suf=t[p].ans=max(w_new[L],0LL);
}else{
int mid=(L+R)/2;
build(L,mid,p*2);
build(mid+1,R,p*2+1);
pushup(t[p],t[2*p],t[2*p+1]);
}
}
void update(int L,int R,int k,int p){
if(t[p].r<L||t[p].l>R)return ;
if(t[p].r==t[p].l){
t[p].tag=k;
t[p].sum=t[p].tag*(t[p].r-t[p].l+1);
t[p].pre=t[p].suf=t[p].ans=max(t[p].sum,0LL);
return ;
}else{
pushdown(p);
update(L,R,k,p*2),update(L,R,k,p*2+1);
pushup(t[p],t[2*p],t[2*p+1]);
}
}
node querysum(int L,int R,int p){
if(t[p].l>R or t[p].r<L or L>R)return {};
if(t[p].l>=L and t[p].r<=R){
return t[p];
} else{
node x,y,z;
y=querysum(L,R,p*2);
z=querysum(L,R,p*2+1);
if(t[p*2+1].l>R||t[p*2+1].r<L)return y;
if(t[p*2].l>R||t[p*2].r<L)return z;
pushup(x,y,z);
return x;
}
}
void updrg(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(dfn[top[x]],dfn[x],k,1);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(dfn[x],dfn[y],k,1);
}
int qyrg(int x,int y){
node a1={},a2={};
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y),swap(a1,a2);
pushup(a1,querysum(dfn[top[x]],dfn[x],1),a1);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y),swap(a1,a2);
pushup(a2,querysum(dfn[x],dfn[y],1),a2);
swap(a1.pre,a1.suf);
pushup(a1,a1,a2);
return a1.ans;
}
int n,q;
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>w[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
add(u,v);add(v,u);
}
dep[1] = 1;
dfs(1,0);
dfs2(1,1);
build(1,n,1);
cin>>q;
while(q--){
int opt;
cin>>opt;
if(opt==1){
int x,y;
cin>>x>>y;
cout<<qyrg(x,y)<<'\n';
}else{
int x,y,k;
cin>>x>>y>>k;
updrg(x,y,k);
}
}
return 0;
}