#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<set>
#include<list>
#include<stack>
#include<queue>
#include<cmath>
#include<functional>
#include<algorithm>
using namespace std;
#define INF (1<<30)


class DouseTree{
	friend class HLDecomposition;
	struct A{
		int left,right,ans,all;
		bool lazyflag;
		int lazyval;
		A& reverse(){
			std::swap(left,right);
			return *this;
		}
	};
	int n;
	mutable std::vector<A> node;
	void update(int a,int b,int x,int k,int l,int r){
		if(r<=a || b<=l)return;
		if(a<=l && r<=b){
			A &v=node[k];
			v.left=v.right=v.ans=x<=0?x:x*(r-l);
			v.all=x*(r-l);
			v.lazyflag=true;
			v.lazyval=x;
			return;
		}
		int m=(l+r)/2;
		if(node[k].lazyflag){
			update(l,r,node[k].lazyval,2*k+1,l,m);
			update(l,r,node[k].lazyval,2*k+2,m,r);
			node[k].lazyflag=false;
		}
		update(a,b,x,2*k+1,l,m);
		update(a,b,x,2*k+2,m,r);
		node[k]=func(node[2*k+1],node[2*k+2]);
	}
	A query(int a,int b,int k,int l,int r){
		if(r<=a || b<=l)return identity();
		if(a<=l && r<=b){
			return node[k];
		}
		int m=(l+r)/2;
		if(node[k].lazyflag){
			update(l,r,node[k].lazyval,2*k+1,l,m);
			update(l,r,node[k].lazyval,2*k+2,m,r);
			node[k].lazyflag=false;
		}
		return func(query(a,b,2*k+1,l,m),query(a,b,2*k+2,m,r));
	}
public:
	static A identity(){
		A res={-INF,-INF,-INF,0,false};
		return res;
	}
	static A func(const A &a,const A &b){
		if(a.left==-INF)return b;
		if(b.left==-INF)return a;
		A res;
		res.left=max(a.left,a.all+b.left);
		res.right=max(b.right,a.right+b.all);
		res.ans=max(max(a.ans,b.ans),a.right+b.left);
		res.all=a.all+b.all;
		res.lazyflag=false;
		return res;
	}
	DouseTree(int n){	
		init(n);
	}
	void init(int n){
		while(n&(n-1))n+=n&-n;
		this->n=n;
		node.assign(2*n-1,identity());
	}
	void update(int a,int b,int x){
		update(a,b,x,0,0,n);
	}
	A query(int a,int b){
		return query(a,b,0,0,n);
	}
};




class LCA{
	int lg,n;
	vector<int> _depth,par;
	void bfs(const vector<int> edge[],int root){
		queue<pair<int,int> > q;
		q.push(make_pair(root,1));
		while(!q.empty()){
			pair<int,int> pi=q.front();
			int u=pi.first;
			_depth[u]=pi.second;
			q.pop();
			for(int i=0;i<(int)edge[u].size();i++){
				q.push(make_pair(edge[u][i],pi.second+1));
			}
		}
	}
	void init(const vector<int> &parent){
		lg=1;
		while((1<<lg)<n)lg++;
		lg++;
		par.resize(n*lg);	
		for(int i=0;i<n;i++)par[i]=parent[i];
		for(int i=1;i<lg;i++)
			for(int v=0;v<n;v++)
				if(par[(i-1)*n+v]!=-1)par[i*n+v]=par[(i-1)*n+par[(i-1)*n+v]];
				else par[i*n+v]=-1;
	}
public:
	LCA(const vector<int> edge[],int n):n(n),_depth(n,0){
		vector<int> parent(n,-1);
		for(int i=0;i<n;i++)
			for(int j=0;j<(int)edge[i].size();j++)parent[edge[i][j]]=i;
		bfs(edge,find(parent.begin(),parent.end(),-1)-parent.begin() );
		init(parent);
	}
	int query(int u,int v)const{
		if(_depth[u] > _depth[v])std::swap(u,v);
		for(int i=lg-1;i>=0;i--)
			if(_depth[u] <= _depth[v]-(1<<i))
				v=par[i*n+v];
		if(u==v)return u;
		for(int i=lg-1;i>=0;i--){
			if(par[i*n+u]!=par[i*n+v]){
				u=par[i*n+u];
				v=par[i*n+v];
			}
		}
		return par[u];
	}
	int depth(int u)const{//rootの深さが1
		return _depth[u];
	}
};



class HLDecomposition{
	struct S{
		pair<int,int> par;
		DouseTree segtree;
		S(int a,int b,vector<int> v):par(a,b),segtree(v.size()){
			for(int i=0;i<(int)v.size();i++){
				segtree.update(i,i+1,v[i]);
			}
		}
	};
	void max_subtree(int u,vector<int> edge[],vector<int> &msz){
		stack<int> st;
		vector<int> size(msz.size());
		st.push(u);
		while(!st.empty()){
			u=st.top();
			st.pop();
			if(u<0){
				u=-u-1;
				int res=0,sz=0,idx=-1;
				for(int i=0;i<(int)edge[u].size();i++){
					int s=size[edge[u][i]];
					if(sz<s){
						sz=s;
						idx=i;
					}
					res+=s;
				}
				size[u]=res+1;
				msz[u]=idx;
			}else{
				st.push(-u-1);
				for(int i=0;i<(int)edge[u].size();i++){
					st.push(edge[u][i]);
				}
			}
		}
	}
	void build(int u,vector<int> edge[],int val[],vector<int> &msz){
		vector<int> heavy;
		int v=u;
		int par=compressed.size(),pi=0,s;
		while(1){
			ver[v]=make_pair(par,heavy.size());
			heavy.push_back(val[v]);
			if(msz[v]==-1)break;
			v=edge[v][msz[v]];
		}
		compressed.push_back(S(-1,-1,heavy));
		heavy.clear();
		while(1){
			for(int i=0;i<(int)edge[u].size();i++){
				if(i==msz[u])continue;
				s=compressed.size();
				build(edge[u][i],edge,val,msz);
				compressed[s].par=make_pair(par,pi);
			}
			if(msz[u]==-1)break;
			u=edge[u][msz[u]];
			pi++;
		}
	}
	mutable vector<S> compressed;
	vector<pair<int,int> > ver;
	LCA lca;
public:
	HLDecomposition(vector<int> edge[],int val[],int n):ver(n),lca(edge,n){
		vector<int> maxsz(n,-1);
		max_subtree(0,edge,maxsz);
		build(0,edge,val,maxsz);
	}
	long long query(int u,int v)const{
		int w=lca.query(u,v);
		pair<int,int> a,b,c;
		a=ver[u];
		b=ver[v];
		c=ver[w];
		DouseTree::A res1,res2;
		res1=res2=DouseTree::identity();
		while(c.first!=a.first){
			res1=DouseTree::func(res1,compressed[a.first].segtree.query(0,a.second+1).reverse());
			a=compressed[a.first].par;
		}
		res1=DouseTree::func(res1,compressed[c.first].segtree.query(c.second,a.second+1).reverse());
		while(c.first!=b.first){
			res2=DouseTree::func(compressed[b.first].segtree.query(0,b.second+1),res2);
			b=compressed[b.first].par;
		}
		res2=DouseTree::func(compressed[c.first].segtree.query(c.second+1,b.second+1),res2);
		return DouseTree::func(res1,res2).ans;
	}
	void update(int u,int v,int x)const{
		int w=lca.query(u,v);
		pair<int,int> a,b,c;
		a=ver[u];
		b=ver[v];
		c=ver[w];
		while(c.first!=a.first){
			compressed[a.first].segtree.update(0,a.second+1,x);
			a=compressed[a.first].par;
		}
		compressed[c.first].segtree.update(c.second,a.second+1,x);
		while(c.first!=b.first){
			compressed[b.first].segtree.update(0,b.second+1,x);
			b=compressed[b.first].par;
		}
		compressed[c.first].segtree.update(c.second+1,b.second+1,x);
	}
};


//uを根とする木の親への辺を削除
void tree_delete_edge(int u,vector<int> edge[],int par=-1){
	queue<pair<int,int> > q;
	q.push(make_pair(u,-1));
	while(!q.empty()){
		pair<int,int> pi=q.front();
		u=pi.first;
		q.pop();
		for(int i=0;i<(int)edge[u].size();i++){
			if(edge[u][i]==pi.second){
				edge[u].erase(edge[u].begin()+i--);
			}else{
				q.push(make_pair(edge[u][i],u));
			}
		}
	}
}

int val[200000];
vector<int> edge[200000];

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n,q;
	cin>>n>>q;
	for(int i=0;i<n;i++)cin>>val[i];
	for(int i=0;i<n-1;i++){
		int s,e;
		cin>>s>>e;
		s--;e--;
		edge[s].push_back(e);
		edge[e].push_back(s);
	}
	tree_delete_edge(0,edge);
	HLDecomposition hl(edge,val,n);
	for(int i=0;i<q;i++){
		int t,a,b,c;
		cin>>t>>a>>b>>c;
		a--;b--;
		if(t==1){
			hl.update(a,b,c);
		}else{
			cout<<hl.query(a,b)<<endl;
		}
	}
	return 0;
}

Measured memory_bytes: 57252