#include <bits/stdc++.h>

int ri() {
	int n;
	scanf("%d", &n);
	return n;
}

struct MaxContSum { // non-empty
	int64_t max = -2000000001;
	int64_t sum = 0;
	int64_t max_left = -2000000001;
	int64_t max_right = -2000000001;
	MaxContSum () = default;
	// size > 0
	MaxContSum (int size, int val) : max(std::max(val, size * val)), sum(size * val), max_left(max), max_right(max) {}
	MaxContSum operator * (const MaxContSum &rhs) const {
		MaxContSum res;
		res.max = std::max({max, rhs.max, max_right + rhs.max_left});
		res.sum = sum + rhs.sum;
		res.max_left = std::max({max_left, sum + rhs.max_left});
		res.max_right = std::max({rhs.max_right, rhs.sum + max_right});
		return res;
	}
	MaxContSum reversed() const {
		MaxContSum res = *this;
		std::swap(res.max_left, res.max_right);
		return res;
	}
};

#define INF 2000000001
struct SegTree {
	int n;
	std::vector<MaxContSum> data;
	std::vector<int> updated;
	SegTree () {}
	SegTree (int n_) {
		for (n = 1; n < n_; n <<= 1);
		data.resize(n << 1);
		updated.resize(n << 1, INF);
	}
	void flush(int i, int len) {
		if (updated[i] != INF) {
			data[i] = MaxContSum(len, updated[i]);
			if (i < n) {
				updated[i << 1] = updated[i];
				updated[i << 1 | 1] = updated[i];
			}
			updated[i] = INF;
		}
	}
	void assign(int l, int r, int val, int node = 1, int node_l = 0, int node_r = 0) {
		if (!node_r) node_r = n;
		flush(node, node_r - node_l);
		if (l >= node_r || r <= node_l) return;
		if (l <= node_l && r >= node_r) {
			updated[node] = val;
			flush(node, node_r - node_l);
		} else {
			int mid = node_l + ((node_r - node_l) >> 1);
			assign(l, r, val, node << 1, node_l, mid);
			assign(l, r, val, node << 1 | 1, mid, node_r);
			data[node] = data[node << 1] * data[node << 1 | 1];
		}
	}
	MaxContSum fold(int l, int r, int node = 1, int node_l = 0, int node_r = 0) {
		if (!node_r) node_r = n;
		flush(node, node_r - node_l);
		if (l >= node_r || r <= node_l) return MaxContSum();
		else if (l <= node_l && r >= node_r) return data[node];
		else {
			int mid = node_l + ((node_r - node_l) >> 1);
			auto res = fold(l, r, node << 1, node_l, mid) * fold(l, r, node << 1 | 1, mid, node_r);
			data[node] = data[node << 1] * data[node << 1 | 1];
			return res;
		}
	}
};
std::vector<std::vector<int> > hen;
std::vector<int> size, parent;
void dfs1(int i, int prev) {
	parent[i] = prev;
	if (prev != -1) hen[i].erase(std::find(hen[i].begin(), hen[i].end(), prev));
	for (auto &j : hen[i]) {
		dfs1(j, i);
		size[i] += size[j];
		if (size[j] > size[hen[i][0]]) std::swap(j, hen[i][0]);
	}
}
std::vector<int> top, chain, depth_local, chain_sizes{0};
void dfs2(int i) {
	chain[i] = chain_sizes.size() - 1;
	depth_local[i] = chain_sizes.back()++;
	for (auto j : hen[i]) {
		if (j == hen[i][0]) top[j] = top[i];
		else top[j] = j, chain_sizes.push_back(0);
		dfs2(j);
	}
}
std::vector<SegTree> trees;
MaxContSum fold_path(int i, int j) {
	MaxContSum l, r;
	while (chain[i] < chain[j]) {
		r = trees[chain[j]].fold(0, depth_local[j] + 1) * r;
		j = parent[top[j]];
	}
	while (chain[i] > chain[j]) {
		l = trees[chain[i]].fold(0, depth_local[i] + 1) * l;
		i = parent[top[i]];
	}
	while (chain[i] < chain[j]) {
		r = trees[chain[j]].fold(0, depth_local[j] + 1) * r;
		j = parent[top[j]];
	}
	if (depth_local[i] < depth_local[j]) r = trees[chain[i]].fold(depth_local[i], depth_local[j] + 1) * r;
	else l = trees[chain[i]].fold(depth_local[j], depth_local[i] + 1) * l;
	
	return l.reversed() * r;
}
void update_path(int i, int j, int val) {
	if (chain[i] > chain[j]) std::swap(i, j);
	while (chain[i] < chain[j]) {
		trees[chain[j]].assign(0, depth_local[j] + 1, val);
		j = parent[top[j]];
	}
	while (chain[i] > chain[j]) {
		trees[chain[i]].assign(0, depth_local[i] + 1, val);
		i = parent[top[i]];
	}
	if (depth_local[i] > depth_local[j]) std::swap(i, j);
	trees[chain[i]].assign(depth_local[i], depth_local[j] + 1, val);
}

int main() {
	int n = ri(), q = ri();
	int a[n];
	for (auto &i : a) i = ri();
	hen.resize(n);
	for (int i = 0; i + 1 < n; i++) {
		int a = ri() - 1;
		int b = ri() - 1;
		hen[a].push_back(b);
		hen[b].push_back(a);
	}
	size.resize(n, 1);
	parent.resize(n);
	dfs1(0, -1);
	top.resize(n);
	chain.resize(n);
	depth_local.resize(n);
	dfs2(0);
	
	int m = chain_sizes.size();
	trees.resize(m);
	for (int i = 0; i < m; i++) trees[i] = SegTree(chain_sizes[i]);
	for (int i = 0; i < n; i++) trees[chain[i]].assign(depth_local[i], depth_local[i] + 1, a[i]);
	for (int i = 0; i < q; i++) {
		int t = ri();
		int x = ri() - 1;
		int y = ri() - 1;
		int c = ri();
		if (t == 1) update_path(x, y, c);
		else printf("%d\n", (int) fold_path(x, y).max);
	}
	
	return 0;
}



Measured memory_bytes: 52764