//Let's join Kaede Takagaki Fan Club !!
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef pair<int,P> P1;
typedef pair<P,P> P2;
#define pu push
#define pb push_back
#define mp make_pair
#define eps 1e-7
#define INF 1000000000
#define fi first
#define sc second
#define rep(i,x) for(int i=0;i<x;i++)
#define repn(i,x) for(int i=1;i<=x;i++)
#define SORT(x) sort(x.begin(),x.end())
#define ERASE(x) x.erase(unique(x.begin(),x.end()),x.end())
#define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
#define all(x) x.begin(),x.end()
template<class T>
void dmp(T a){
	rep(i,a.size()) cout << a[i] << " ";
	cout << endl;
}
template<class T>
bool chmax(T&a, T b){
	if(a < b){
		a = b;
		return 1;
	}
	return 0;
}
template<class T>
bool chmin(T&a, T b){
	if(a > b){
		a = b;
		return 1;
	}
	return 0;
}
template<class T>
void g(T &a){
	cin >> a;
}
template<class T>
void o(const T &a,bool space=false){
	cout << a << (space?' ':'\n');
}
//ios::sync_with_stdio(false);
const ll mod = 1000000007;//998244353
template<class T>
void add(T&a,T b){
	a+=b;
	if(a >= mod) a-=mod;
}

struct dat {
	int sz, val, sum, lmx, rmx, mv, ans;
};
dat dt(int v){
    dat d;
    d.sz = 1;
    d.val = d.sum = d.mv = v;
    d.lmx = d.rmx = d.ans = max(0, v);
    return d;
}
dat dt(int v, int c){
    dat d;
    d.sz = c;
    d.val = d.mv = v;
    d.sum = v*c;
    d.lmx = d.rmx = d.ans = max(0, v*c);
    return d;
}
dat mrg(dat a, dat b, bool left){
	return {a.sz+b.sz, (left?a:b).val, a.sum+b.sum, max(a.lmx, a.sum+b.lmx), max(b.rmx, b.sum+a.rmx), max(a.mv, b.mv), max(max(a.ans, b.ans), a.rmx+b.lmx)};
}

struct node{
	node *l, *r, *p;
	int id, lazy, rev;
	dat D;
	node(int i, int v) : l(0), r(0), p(0), id(i), lazy(INF), rev(0){
		D = dt(v);
	}
};

inline bool is_root(node *n){
	return n -> p == NULL || n -> p -> l != n && n -> p -> r != n;
}

inline bool left(node *n){
	return n == n -> p -> l;
}
//n->lazyが実際の値
//push(n)を走らせた後にはn->l と n->r の値は正しく計算されている必要あり
inline void evaluate(node *n){
    n->D = dt(n->lazy, n->D. sz);
}

//遅延評価
inline void push(node *n){
	if(n->rev){
		swap(n->l, n->r);
		if(n->l){
			n->l->rev ^= 1;
			swap(n->l->D. lmx, n->l->D. rmx);
		}
		if(n->r){
			n->r->rev ^= 1;
			swap(n->r->D. lmx, n->r->D. rmx);
		}
		n->rev = 0;
	}
	if(n->lazy == INF) return;
	
	if(n->l){
		n->l->lazy = n->lazy;
		evaluate(n->l);
	}
	if(n->r){
		n->r->lazy = n->lazy;
		evaluate(n->r);
	}
	n->lazy = INF;
}

//値の再計算
inline void update(node *n){
	//最初に遅延評価
	push(n);
	dat slf = dt(n->D. val);
	if(n->l) slf = mrg(n->l->D, slf, false);
	if(n->r) slf = mrg(slf, n->r->D, true);
	n->D = slf;
}
inline void connect(node *n, node *p, bool l){
	(l ? p -> l : p -> r) = n;
	if(n) n -> p = p;
}
//rotateが呼ばれる前には関与しているノードの遅延評価をする必要がある
inline void rotate(node *n){
	node *p = n -> p, *g = p -> p;
	bool l = left(n);
	connect(l ? n -> r : n -> l, p, l);
	if(!is_root(p)) connect(n, g, left(p));
	else n -> p = g;
	connect(p, n, !l);
	update(p), update(n);
}
inline void splay(node *n){
    if(is_root(n)){
        update(n);
        return;
    }
	while(!is_root(n)){
		node *p = n -> p, *g = p -> p;
		//関与する頂点群の遅延評価をする
		if(!is_root(p)) push(g);
		push(p), push(n);
		if(!is_root(p)) rotate(left(n) ^ left(p) ? n : p);
		rotate(n);
	}
}
//返り値はnじゃないよ
inline node* expose(node *n){
	node *last = NULL;
	for(node *m = n; m; m = m -> p){
		splay(m);
		m -> r = last;
		last = m;
	}
	splay(n);
	return last;
}
inline void link(node *m, node *n){
	expose(m), expose(n);
	m -> p = n;
}
inline void cut(node *n){
	expose(n);
	n -> l -> p = NULL;
	n -> l = NULL;
	update(n);
}
inline void evert(node *n){
	expose(n);
	n->rev ^= 1;
	swap(n->D.lmx, n->D.rmx);
}
inline void make(node *n, int v){
	expose(n);
	n->lazy = v;
	evaluate(n);
}
inline int get(node *n){
	expose(n);
	if(n->D.mv < 0) return n->D.mv;
	else return n->D.ans;
}

const int MAXN = 200005;
node *V[MAXN];
int n,q,w[MAXN];

int main(){
	scanf("%d%d",&n,&q);
	repn(i,n){
		scanf("%d",&w[i]);
		V[i] = new node(i, w[i]);
	}
	rep(i,n-1){
		int a, b; scanf("%d%d",&a,&b);
		evert(V[a]);
		link(V[a], V[b]);
	}
	rep(i,q){
		int t, a, b, c; scanf("%d%d%d%d",&t,&a,&b,&c);
		if(t == 1){
			evert(V[a]);
			make(V[b], c);
		}
		else{
			evert(V[a]);
			printf("%d\n",get(V[b]));
		}
	}
}


Measured memory_bytes: 21212