import std.stdio;
import core.stdc.stdio;
import core.memory;
import std.algorithm;
import std.typecons;

int TopBit(int a){
	for(int i=18;i>=0;i--)
		if((1<<i)&a) return i;
	return -1;
}

alias Tuple!(int,"val",int,"idx") vi;

struct SparseTable{
	vi[][] st;
	void Initialize(vi[] d){
		int h=TopBit(d.length)+1;
		st = new vi[][](h,d.length);
		for(int i=0;i<d.length;i++) st[0][i] = d[i];
		for(int j=1;j<h;j++) for(int i=0;i<d.length-(1<<j)+1;i++) st[j][i] = min(st[j-1][i],st[j-1][i+(1<<(j-1))]);
	}
	vi get(int begin,int end){
		int h = TopBit(end-begin);
		return min(st[h][begin],st[h][end-(1<<h)]);
	}
}

int[][] tree;
int[] subTreeCount;

struct LCA{
	SparseTable st;
	vi[] eulertour;
	int[] firstIdx;
	int ei=0;
	int sc=0;
	void DFS(int idx,int depth,int par){
		firstIdx[idx] = ei;
		eulertour[ei++] = vi(depth,idx);
		subTreeCount[idx] = -(sc++);
		foreach(c;tree[idx]){
			if(c==par)
				continue;
			DFS(c,depth+1,idx);
			eulertour[ei++] = vi(depth,idx);
		}
		subTreeCount[idx] += sc;
	}
	void Initialize(){
		eulertour = new vi[n*2];
		firstIdx = new int[n];
		DFS(0,0,-1);
		st.Initialize(eulertour[0..ei]);
	}
	int get(int a,int b){
		a = firstIdx[a];
		b = firstIdx[b];
		if(a>b) swap(a,b);
		return st.get(a,b+1).idx;
	}
}

alias Tuple!(int,"l",int,"r",int,"m",int,"a") sums;
sums mergeSums(sums a,sums b){
	sums ret;
	ret.l = max(a.l,a.a+b.l);
	ret.m = max(a.m,b.m,a.r+b.l);
	ret.r = max(a.r + b.a,b.r);
	ret.a = a.a+b.a;
	return ret;
}


class SegmentTree{
	sums[] data;
	int[] delay;
	int size;
	void Initialize(int[] d){
		size = 1;
		while(size<d.length)size*=2;
		data = new sums[size*2];
		delay = new int[size*2];
		for(int i=size;i<size+d.length;i++)
			data[i] = sums(d[i-size],d[i-size],d[i-size],d[i-size]);
		for(int i=size-1;i>=1;i--)
			data[i] = mergeSums(data[i*2],data[i*2+1]);
		for(int i=1;i<size*2;i++)
			delay[i] = int.min;
	}
	void passDelay(int idx,int s){
		if(delay[idx]<0){
			data[idx].l = delay[idx];
			data[idx].r = delay[idx];
			data[idx].m = delay[idx];
		}else{
			data[idx].l = delay[idx]*s;
			data[idx].r = delay[idx]*s;
			data[idx].m = delay[idx]*s;
		}
		data[idx].a = delay[idx]*s;
		if(idx<size){
			delay[idx*2] = delay[idx];
			delay[idx*2+1] = delay[idx];
		}
		delay[idx] = int.min;
	}
	int begin;
	int end;
	int w;
	void _update(int idx,int l,int r){
		if(end<=l||r<=begin)
			return;
		if(begin<=l&&r<=end){
			delay[idx] = w;
			return;
		}
		if(delay[idx] != int.min){
			delay[idx*2] = delay[idx];
			delay[idx*2+1] = delay[idx];
			delay[idx] = int.min;
		}
		_update(idx*2,l,(l+r)/2);
		_update(idx*2+1,(l+r)/2,r);
		if(delay[idx*2] != int.min)
			passDelay(idx*2,(r-l)/2);
		if(delay[idx*2+1] != int.min)
			passDelay(idx*2+1,(r-l)/2);
		data[idx] = mergeSums(data[idx*2],data[idx*2+1]);
	}
	void Update(int _begin,int _end,int _w){
		if(_begin>=_end)
			return;
		begin = _begin;
		end = _end;
		w = _w;
		_update(1,0,size);
	}
	sums get(int idx,int l,int r){
		if(begin<=l&&r<=end){
			if(delay[idx] != int.min)
				passDelay(idx,r-l);
			return data[idx];
		}
		if(begin>=(l+r)/2)
			return get(idx*2+1,(l+r)/2,r);
		if(end<=(l+r)/2)
			return get(idx*2,l,(l+r)/2);
		return mergeSums(get(idx*2,l,(l+r)/2),get(idx*2+1,(l+r)/2,r));
	}
	sums Get(int _begin,int _end){
		begin = _begin;
		end = _end;
		return get(1,0,size);
	}
}

int n;
int[] weights;

struct HLdecomposition{
	LCA lca;
	int[] group;
	int[] invPath;
	int[] gsize;
	int[] pathData;
	int[][]	paths;
	int[] pathParent;
	SegmentTree[] segs;
	int gi=0;
	void DFS(int idx,int g,int p,int par){
		group[idx] = g;
		invPath[idx] = p;
		int maxsc=0;
		int midx=-1;
		foreach(c;tree[idx]){
			if(c==par)
				continue;
			if(subTreeCount[c] > maxsc){
				maxsc = subTreeCount[c];
				midx = c;
			}
		}
		foreach(c;tree[idx]){
			if(c==par)
				continue;
			if(c == midx)
				DFS(c,g,p+1,idx);
			else{
				pathParent[gi] = idx;
				DFS(c,gi++,0,idx);
			}
		}
		if(midx == -1)
			gsize[g] = p+1;
	}
	void Initialize(){
		group = new int[n];
		invPath = new int[n];
		gsize = new int[n];
		pathData = new int[n];
		paths = new int[][n];
		pathParent = new int[n];
		lca.Initialize;
		pathParent[0] = -1;
		DFS(0,gi++,0,-1);
		int pidx=0;
		for(int i=0;i<gi;i++){
			paths[i] = pathData[pidx..pidx+gsize[i]];
			pidx += gsize[i];
		}
		for(int i=0;i<n;i++){
			paths[group[i]][invPath[i]] = weights[i];
		}
		segs = new SegmentTree[gi];
		for(int i=0;i<gi;i++){
			segs[i] = new SegmentTree;
			segs[i].Initialize(paths[i]);
		}
	}
	void _update(int a,int b,int w){
		while(group[a] != group[b]){
			segs[group[a]].Update(0,invPath[a]+1,w);
			a = pathParent[group[a]];
		}
		segs[group[a]].Update(invPath[b],invPath[a]+1,w);
	}
	void Update(int a,int b,int w){
		int lc = lca.get(a,b);
		_update(a,lc,w);
		_update(b,lc,w);
	}
	sums _get(int a,int b){
		sums ret = sums(int.min,int.min,int.min,int.min);
		sums g;
		while(group[a] != group[b]){
			g = segs[group[a]].Get(0,invPath[a]+1);
			if(ret.a == int.min)
				ret = g;
			else
				ret = mergeSums(g,ret);
			a = pathParent[group[a]];
		}
		g = segs[group[a]].Get(invPath[b],invPath[a]+1);
		if(ret.a == int.min)
			return g;
		else
			return mergeSums(g,ret);
	}
	int Get(int a,int b){
		int lc = lca.get(a,b);
		sums as = _get(a,lc);
		sums bs = _get(b,lc);
		return max(as.m,bs.m,as.l+bs.l-segs[group[lc]].Get(invPath[lc],invPath[lc]+1).a);
	}
}

HLdecomposition hl;

void main(){
	int q;
	scanf("%d%d",&n,&q);
	tree = new int[][n];
	subTreeCount = new int[n];
	weights = new int[n];
	int[] ans = new int[q];
	for(int i=0;i<n;i++)
		scanf("%d",&weights[i]);
	for(int i=0;i<n-1;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		tree[--a] ~= --b;
		tree[b] ~= a;
	}
	hl.Initialize;
	int qc=0;
	for(int i=0;i<q;i++){
		int t,a,b,c;
		scanf("%d%d%d%d",&t,&a,&b,&c);
		if(t == 1){
			hl.Update(a-1,b-1,c);
		}else if(t==2){
			ans[qc++] = hl.Get(a-1,b-1);
		}
	}
	for(int i=0;i<qc;i++)
		printf("%d\n",ans[i]);
}