#ifdef DEBUG
#define GNU_DEBUG
#define _GLIBCXX_DEBUG 1
#define _GLIBCXX_DEBUG_PEDANTIC 1
#define _GLIBCXX_SANITIZE_VECTOR 1
#endif
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define F(i,j,k) for(auto i=j;i<=(decltype(i))k;i++)
#define exec(...) [&](){__VA_ARGS__}()
#define lambda [&]
#define endl '\n'
#define view(x) begin(x),end(x)
#define pb push_back
#define x first
#define y second
#define os ostream
using namespace std;
using namespace __gnu_pbds;
template<typename T>void ckmax(T& a,T b){a=max(a,b);}
template<typename T>void ckmin(T& a,T b){a=min(a,b);}
#ifdef DEBUG
template<typename T1,typename T2>os& operator<<(os& out,pair<T1,T2> x){return out<<tuple(x);}
template<typename T,typename=decltype(T().begin()),typename=enable_if_t<!is_same_v<decay_t<T>,string>>>os& operator<<(os& out,T x){return out<<"{",exec(auto n=0u;for(auto i:x) out<<i<<(++n==x.size()?"":",");),out<<"}";}
template<typename...T>os& operator<<(os& out,tuple<T...> x){return apply(lambda(T... xx){auto n=0u;out<<"{",((out<<xx<<(++n==sizeof...(T)?"":",")),...),out<<"}";},x),out;}
#define debug(...) cerr<<"#"<<__LINE__<<": "<<#__VA_ARGS__<<" = "<<std::make_tuple(__VA_ARGS__)<<endl
#else
#define debug(...) (void)0
#endif
#define nodebug(...) (void)0
const int maxn=1e5+5;
#define int long long
int n,q,op,x,y,mson[maxn],id[maxn],siz[maxn];
int top[maxn],cnt,fa[maxn],dep[maxn],val[maxn],z;
vector<int> v[maxn];
struct Node{
int sum,lmx,rmx,mx;
}w[maxn];
Node merge(const Node& n1,const Node& n2){
return {
n1.sum+n2.sum,
max(n1.lmx,n1.sum+n2.lmx),
max(n2.rmx,n2.sum+n1.rmx),
max({n1.rmx+n2.lmx,n1.mx,n2.mx})
};
}
void dfs1(int u,int f){
siz[u]=1;
fa[u]=f;
dep[u]=dep[f]+1;
for(auto i:v[u]) if(i!=f){
dfs1(i,u);
siz[u]+=siz[i];
if(siz[mson[u]]<siz[i]) mson[u]=i;
}
}
void dfs2(int u,int tp){
cnt++;
id[u]=cnt,top[u]=tp;
w[cnt]={val[u],max(val[u],0ll),max(val[u],0ll),max(val[u],0ll)};
if(mson[u]) dfs2(mson[u],tp);
for(auto i:v[u]) if(i!=fa[u]&&i!=mson[u]) dfs2(i,i);
}
#define ls node*2
#define rs node*2+1
#define mid (l+r)/2
#define pkgl l,mid,ls
#define pkgr mid+1,r,rs
struct Segment{
Node t[maxn*4];
int tag[maxn*4];
bool vis[maxn*4];
Segment(){
memset(t,0,sizeof t);
memset(tag,0,sizeof tag);
memset(vis,0,sizeof vis);
}
void push_up(int node){t[node]=merge(t[ls],t[rs]);}
void build(int l,int r,int node){
if(l==r) return t[node]=w[l],(void)0;
build(pkgl),build(pkgr);
push_up(node);
}
void updtag(int l,int r,int node,int want){
t[node].sum=(r-l+1)*want;
t[node].lmx=t[node].rmx=t[node].mx=max(t[node].sum,0ll);
tag[node]=want;
vis[node]=1;
}
void push_down(int l,int r,int node){
if(vis[node]){
updtag(pkgl,tag[node]);
updtag(pkgr,tag[node]);
vis[node]=0;
}
}
void update(int l,int r,int node,int x,int y,int want){
if(x<=l&&r<=y) return updtag(l,r,node,want),vis[node]=1,(void)0;
push_down(l,r,node);
if(mid>=x) update(pkgl,x,y,want);
else update(pkgr,x,y,want);
push_up(node);
}
Node query(int l,int r,int node,int x,int y){
if(x<=l&&r<=y) return t[node];
push_down(l,r,node);
if(mid>=x){
if(mid<y) return merge(query(pkgl,x,y),query(pkgr,x,y));
else return query(pkgl,x,y);
}
else return query(pkgr,x,y);
}
}t;
void updLine(int x,int y,int c){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
t.update(1,n,1,id[top[x]],id[x],c);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
t.update(1,n,1,id[y],id[x],c);
}
int qryLine(int x,int y){
Node ans1={0,0,0,0},ans2={0,0,0,0};
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]){
ans2=merge(t.query(1,n,1,id[top[y]],id[y]),ans2);
y=fa[top[y]];
}
else{
ans1=merge(t.query(1,n,1,id[top[x]],id[x]),ans1);
x=fa[top[x]];
}
}
if(dep[x]>dep[y]) ans1=merge(t.query(1,n,1,id[y],id[x]),ans1);
else ans2=merge(t.query(1,n,1,id[x],id[y]),ans2);
swap(ans1.lmx,ans2.rmx);
return merge(ans1,ans2).mx;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
F(i,1,n) cin>>val[i];
F(i,1,n-1) cin>>x>>y,v[x].pb(y),v[y].pb(x);
cin>>q;
dfs1(1,1),dfs2(1,1);
t.build(1,n,1);
F(i,1,q){
cin>>op>>x>>y;
if(op==1) cout<<qryLine(x,y)<<endl;
else cin>>z,updLine(x,y,z);
}
return 0;
}