#include <bits/stdc++.h>
using namespace std;

#define dump(...) cout<<"# "<<#__VA_ARGS__<<'='<<(__VA_ARGS__)<<endl
#define repi(i,a,b) for(int i=int(a);i<int(b);i++)
#define peri(i,a,b) for(int i=int(b);i-->int(a);)
#define rep(i,n) repi(i,0,n)
#define per(i,n) peri(i,0,n)
#define all(c) begin(c),end(c)
#define mp make_pair
#define mt make_tuple

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<string> vs;

constexpr ll INF=1e18;
constexpr int MOD=1e9+7;
constexpr double EPS=1e-9;

template<typename T1,typename T2>
ostream& operator<<(ostream& os,const pair<T1,T2>& p){
	return os<<'('<<p.first<<','<<p.second<<')';
}
template<typename Ostream,typename Container>
Ostream& operator<<(Ostream& os,const Container& c){
	os<<'[';
	for(auto i=begin(c);i!=end(c);++i)
		os<<(i==begin(c)?"":" ")<<*i;
	return os<<']';
}

struct Edge{
	int src,dst;
	Edge(){}
	Edge(int s,int d):src(s),dst(d){}
};
typedef vector<vector<Edge>> Graph;

//int DFS1(const Graph& g,int p,int u,vi& sizes)
//{
//	for(auto e:g[u]) if(e.dst!=p)
//		sizes[u]+=DFS1(g,u,e.dst,sizes);
//	return sizes[u];
//}
//void DFS2(const Graph& g,int p,int u,const vi& sizes,vi& path,vvi& paths)
//{
//	path.push_back(u);
//	for(auto e:g[u]){
//		int v=e.dst;
//		if(v==p) continue;
//		if(sizes[v]*2>=sizes[u])
//			DFS2(g,u,v,sizes,path,paths);
//		else{
//			vi tmp;
//			DFS2(g,u,v,sizes,tmp,paths);
//		}
//	}
//	if(path[0]==u)
//		paths.push_back(path);
//}
vvi HeavyLightDecomposition(const Graph& g,int root=0)
{
	int n=g.size();
	vi sizes(n,1);
	//DFS1(g,-1,root,sizes);
	{
		stack<pii> st; st.emplace(-1,root);
		vi vis(n);
		while(st.size()){
			int p,u; tie(p,u)=st.top();
			if(!vis[u]){
				vis[u]=1;
				for(auto e:g[u]) if(e.dst!=p)
					st.emplace(u,e.dst);
			}
			else{
				for(auto e:g[u]) if(e.dst!=p)
					sizes[u]+=sizes[e.dst];
				st.pop();
			}
		}
	}
	//vi path;
	//vvi paths;
	//DFS2(g,-1,root,sizes,path,paths);
	vvi paths(1);
	{
		stack<tuple<int,int,int>> st; st.emplace(-1,root,0);
		vi vis(n);
		while(st.size()){
			int p,u,i; tie(p,u,i)=st.top();
			if(!vis[u]){
				paths[i].push_back(u);
				for(auto e:g[u]) if(e.dst!=p){
					if(sizes[e.dst]*2>=sizes[u])
						st.emplace(u,e.dst,i);
					else{
						paths.push_back(vi());
						st.emplace(u,e.dst,paths.size()-1);
					}
				}
				vis[u]=1;
			}
			else{
				st.pop();
			}
		}
	}
	return paths;
}

vi GetParents(const Graph& g,int root=0)
{
	vi ps(g.size(),-1);
	queue<int> q; q.push(root);
	while(q.size()){
		int u=q.front(); q.pop();
		for(auto e:g[u]) if(e.dst!=ps[u]){
			ps[e.dst]=u;
			q.push(e.dst);
		}
	}
	return ps;
}

struct LCA{
	vi ds;
	vvi ps;
	LCA(const Graph& g,int root=0):ds(g.size()),ps(32-__builtin_clz(g.size()),vi(g.size(),-1)){
		//DFS(g,-1,root,0);
		{
			stack<tuple<int,int,int>> st; st.emplace(-1,root,0);
			while(st.size()){
				int p,v,d; tie(p,v,d)=st.top(); st.pop();
				ds[v]=d;
				ps[0][v]=p;
				for(auto e:g[v]) if(e.dst!=p)
					st.emplace(v,e.dst,d+1);
			}
		}
		rep(i,ps.size()-1) rep(j,ps[i].size())
			ps[i+1][j]=ps[i][j]==-1?-1:ps[i][ps[i][j]];
	}
	//void DFS(const Graph& g,int p,int v,int d){
	//	ds[v]=d;
	//	ps[0][v]=p;
	//	for(auto e:g[v]) if(e.dst!=p)
	//		DFS(g,e.src,e.dst,d+1);
	//}
	int Find(int u,int v){
		if(ds[u]>ds[v]) swap(u,v);
		rep(i,ps.size())
			if((ds[v]-ds[u])>>i&1)
				v=ps[i][v];
		if(u==v) return u;
		per(i,ps.size())
			if(ps[i][u]!=ps[i][v])
				u=ps[i][u],v=ps[i][v];
		return ps[0][u];
	}
};

int NextPow2(int x)
{
	x--;
	for(int i=1;i<32;i*=2) x|=x>>i;
	return x+1;
}

struct SegmentTree{
	int size;
	vl sums,maxs,lmaxs,rmaxs,props;
	vi flags;
	SegmentTree(int n)
		:size(NextPow2(n)),sums(size*2),maxs(size*2,-INF),
		 lmaxs(size*2,-INF),rmaxs(size*2,-INF),props(size*2),flags(size*2){}
	void Update(int ql,int qr,ll x){Update(ql,qr,x,1,0,size);}
	tuple<ll,ll,ll,ll> Query(int ql,int qr){return Query(ql,qr,1,0,size);}
	
	void Propagate(int i){
		if(!flags[i]) return;
		flags[i]=0;
		if(i<size){
			props[i*2]=props[i*2+1]=props[i];
			flags[i*2]=flags[i*2+1]=1;
			rep(j,2){
				props[i*2+j]=props[i];
				flags[i*2+j]=1;
				sums[i*2+j]=sums[i]/2;
				maxs[i*2+j]=lmaxs[i*2+j]=rmaxs[i*2+j]=max(sums[i*2+j],props[i]);
			}
		}
	}
	void Update(int ql,int qr,ll x,int i,int l,int r){
		if(qr<=l || r<=ql) return;
		if(ql<=l && r<=qr){
			props[i]=x;
			flags[i]=1;
			sums[i]=x*(r-l);
			maxs[i]=lmaxs[i]=rmaxs[i]=max(sums[i],x);
			return;
		}
		Propagate(i);
		Update(ql,qr,x,i*2,l,(l+r)/2);
		Update(ql,qr,x,i*2+1,(l+r)/2,r);
		sums[i]=sums[i*2]+sums[i*2+1];
		maxs[i]=max({maxs[i*2],maxs[i*2+1],rmaxs[i*2]+lmaxs[i*2+1]});
		lmaxs[i]=max(lmaxs[i*2],sums[i*2]+lmaxs[i*2+1]);
		rmaxs[i]=max(rmaxs[i*2+1],rmaxs[i*2]+sums[i*2+1]);
	}
	tuple<ll,ll,ll,ll> Query(int ql,int qr,int i,int l,int r){
		if(qr<=l || r<=ql) return mt(0,-INF,-INF,-INF);
		if(ql<=l && r<=qr) return mt(sums[i],maxs[i],lmaxs[i],rmaxs[i]);
		Propagate(i);
		ll s1,m1,l1,r1; tie(s1,m1,l1,r1)=Query(ql,qr,i*2,l,(l+r)/2);
		ll s2,m2,l2,r2; tie(s2,m2,l2,r2)=Query(ql,qr,i*2+1,(l+r)/2,r);
		return mt(s1+s2,max({m1,m2,r1+l2}),max(l1,s1+l2),max(r2,r1+s2));
	}
};

int main()
{
	#ifndef _GLIBCXX_DEBUG
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	constexpr char endl='\n';
	#endif
	
	for(int n,q;cin>>n>>q && n|q;){
		vi ws(n);
		rep(i,n) cin>>ws[i];
		Graph g(n);
		rep(i,n-1){
			int u,v; cin>>u>>v; u--,v--;
			g[u].emplace_back(u,v);
			g[v].emplace_back(v,u);
		}
		
		vvi paths=HeavyLightDecomposition(g);
		vi parents=GetParents(g);
		vi is(n),js(n);
		rep(i,paths.size()) rep(j,paths[i].size())
			is[paths[i][j]]=i,js[paths[i][j]]=j;
		
		vector<SegmentTree> sts;
		for(const auto& path:paths){
			int size=path.size();
			SegmentTree st(size);
			rep(i,size) st.Update(i,i+1,ws[path[i]]);
			sts.push_back(st);
		}
		
		LCA lca(g);
		
		rep(_,q){
			int t,u,v,x; cin>>t>>u>>v>>x; u--,v--;
			int a=lca.Find(u,v);
			if(t==1){ // update
				for(;;){
					int left=is[u]==is[a]?js[a]:0;
					sts[is[u]].Update(left,js[u]+1,x);
					if(is[u]==is[a]) break;
					else u=parents[paths[is[u]][0]];
				}
				for(;;){
					int left=is[v]==is[a]?js[a]+1:0;
					sts[is[v]].Update(left,js[v]+1,x);
					if(is[v]==is[a]) break;
					else v=parents[paths[is[v]][0]];
				}
			}
			else{ // query
				ll m1=-INF,l1=-INF;
				for(;;){
					int left=is[u]==is[a]?js[a]:0;
					ll s,m,l,r; tie(s,m,l,r)=sts[is[u]].Query(left,js[u]+1);
					tie(m1,l1)=mt(max({m,m1,r+l1}),max(l,s+l1));
					if(is[u]==is[a]) break;
					else u=parents[paths[is[u]][0]];
				}
				ll m2=-INF,l2=-INF;
				for(;;){
					int left=is[v]==is[a]?js[a]+1:0;
					ll s,m,l,r; tie(s,m,l,r)=sts[is[v]].Query(left,js[v]+1);
					tie(m2,l2)=mt(max({m,m2,r+l2}),max(l,s+l2));
					if(is[v]==is[a]) break;
					else v=parents[paths[is[v]][0]];
				}
				cout<<max({m1,m2,l1+l2})<<endl;
			}
		}
	}
}

Measured memory_bytes: 113776