Problem: Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and output a value for each output query. The given tree is connected and each node on the tree has a weight wi (-10,000 ≤ wi ≤ 10,000).

Each query consists of a number ti (ti = 1, 2), which indicates the type of the query , and three numbers ai, bi and ci (1 ≤ ai, bi ≤ n, -10,000 ≤ ci ≤ 10,000). Depending on the query type, process one of the followings:

* (ti = 1: modification query) Change the weights of all nodes on the shortest path between ai and bi (both inclusive) to ci.

* (ti = 2: output query) First, create a list of weights on the shortest path between ai and bi (both inclusive) in order. After that, output the maximum sum of a non-empty continuous subsequence of the weights on the list. ci is ignored for output queries.



Input

The first line contains two integers n and q. On the second line, there are n integers which indicate w1, w2, ... , wn.

Each of the following n - 1 lines consists of two integers si and ei (1 ≤ si, ei ≤ n), which means that there is an edge between si and ei.

Finally the following q lines give the list of queries, each of which contains four integers in the format described above. Queries must be processed one by one from top to bottom.

Output

For each output query, output the maximum sum in one line.

Examples

Input

3 4
1 2 3
1 2
2 3
2 1 3 0
1 2 2 -4
2 1 3 0
2 2 2 0


Output

6
3
-4


Input

7 5
-8 5 5 5 5 5 5
1 2
2 3
1 4
4 5
1 6
6 7
2 3 7 0
2 5 2 0
2 4 3 0
1 1 1 -1
2 3 7 0


Output

12
10
10
19


Input

21 30
10 0 -10 -8 5 -5 -4 -3 1 -2 8 -1 -7 2 7 6 -9 -6 3 4 9
10 3
3 2
3 12
12 4
4 13
4 9
10 21
21 1
1 11
11 14
1 15
10 6
6 17
6 16
6 5
5 18
5 19
10 7
10 8
8 20
1 1 21 -10
1 3 19 10
2 1 13 0
1 4 18 8
1 5 17 -5
2 16 7 0
1 6 16 5
1 7 15 4
2 4 20 0
1 8 14 3
1 9 13 -1
2 9 18 0
1 10 12 2
1 11 11 -8
2 21 15 0
1 12 10 1
1 13 9 7
2 6 14 0
1 14 8 -2
1 15 7 -7
2 10 2 0
1 16 6 -6
1 17 5 9
2 12 17 0
1 18 4 6
1 19 3 -3
2 11 8 0
1 20 2 -4
1 21 1 -9
2 5 19 0


Output

20
9
29
27
10
12
1
18
-2
-3

Solution (in CPP):

Solution:
#define _CRT_SECURE_NO_WARNINGS
#define NDEBUG
#include <cassert>
#include <utility>
#include <vector>
#include<functional>

template <typename ValueMonoid, typename OperatorMonoid, class Modify>
class LinkCutTree {
public:
	using value_type = ValueMonoid;
	using operator_type = OperatorMonoid;

private:
	struct node_t {
		node_t *left, *right, *par;
		value_type value, sum;
		operator_type lazy;
		bool isroot, reversed;
		node_t()
			: left(nullptr), right(nullptr), par(nullptr), value(), sum(), lazy(),
			isroot(1), reversed(0) {}
		node_t(node_t *const l, node_t *const r, node_t *const p,
			const value_type &v)
			: left(l), right(r), par(p), value(v), sum(v), lazy(), isroot(1),
			reversed(0) {}
		bool isleft() const { return par->left == this; }
		void assign(const operator_type &data) { lazy = lazy + data; }
		void haulL(node_t *const t) { left = t, t->par = this; }
		void haulR(node_t *const t) { right = t, t->par = this; }
	};
	value_type reflect(const node_t *const t) const {
		return m(t->reversed ? ~t->sum : t->sum, t->lazy);
	}
	void recalc(node_t *const t) {
		t->sum = reflect(t->left) + t->value + reflect(t->right);
	}
	void splay(node_t *const t) {
		node_t *p, *pp = t, *x = t->par;
		while (!t->isroot) {
			(x->left == pp ? x->left : x->right) = t;
			p = t->par;
			if (p->isroot) {
				t->par = p->par;
				std::swap(t->isroot, p->isroot);
				if (p->left == t)
					p->haulL(t->right), t->haulR(p);
				else
					p->haulR(t->left), t->haulL(p);
				recalc(p);
				break;
			}
			pp = p->par;
			x = pp->par;
			std::swap(t->isroot, pp->isroot);
			if (t->isleft()) {
				if (p->isleft())
					pp->haulL(p->right), p->haulR(pp);
				else
					pp->haulR(t->left), t->haulL(pp);
				p->haulL(t->right);
				t->haulR(p);
			}
			else {
				if (p->isleft())
					pp->haulL(t->right), t->haulR(pp);
				else
					pp->haulR(p->left), p->haulL(pp);
				p->haulR(t->left);
				t->haulL(p);
			}
			recalc(pp);
			recalc(p);
			t->par = x;
		}
	}
	void push(node_t *const t) {
		t->left->assign(t->lazy);
		t->right->assign(t->lazy);
		t->value = m(t->value, t->lazy);
		t->lazy = operator_type();
		if (!t->reversed)
			return;
		std::swap(t->left, t->right);
		t->left->reversed ^= 1;
		t->right->reversed ^= 1;
		t->value = ~t->value;
		t->reversed = 0;
	}
	void propagate(node_t *t) {
		node_t *prev = nullptr;
		do {
			std::swap(t->par, prev);
			std::swap(t, prev);
		} while (t != nil);
		do {
			push(prev);
			std::swap(prev->par, t);
			std::swap(prev, t);
		} while (prev);
		nil->lazy = operator_type();
	}
	void expose(node_t *const n) {
		propagate(n);
		node_t *x = n, *prev = nil;
		do {
			splay(x);
			x->right->isroot = 1;
			x->right = prev;
			prev->isroot = 0;
			recalc(x);
			prev = x;
			x = x->par;
		} while (x != nil);
		splay(n);
		recalc(n);
	}
	using container_type = std::vector<node_t>;

public:
	using size_type = typename container_type::size_type;

private:
	node_t *const nil;
	const Modify m;
	container_type tree;
	void reroot(const size_type v) {
		expose(&tree[v]);
		tree[v].reversed ^= 1;
	}

public:
	explicit LinkCutTree(const size_type size, const Modify &m = Modify())
		: m(m), nil(new node_t), tree(size, node_t(nil, nil, nil, value_type())) {
	}
	explicit LinkCutTree(const std::vector<value_type> &a,
		const Modify &m = Modify())
		: m(m), nil(new node_t) {
		tree.reserve(a.size());
		for (const auto &e : a)
			tree.emplace_back(nil, nil, nil, e);
	}
	~LinkCutTree() { delete nil; }
	void link(const size_type child, const size_type parent) {
		assert(child < size());
		assert(parent < size());
		reroot(child);
		tree[child].par = &tree[parent];
	}
	void cut(const size_type child) {
		assert(child < size());
		node_t *const n = &tree[child];
		expose(n);
		n->left->isroot = 1;
		n->left->par = nil;
		n->left = nil;
		n->sum = n->value;
	}
	bool connected(const size_type u, const size_type v) {
		assert(u < size());
		assert(v < size());
		expose(&tree[u]);
		expose(&tree[v]);
		return tree[u].par != nil;
	}
	void update(const size_type v,
		const std::function<value_type(const value_type &)> &f) {
		assert(v < size());
		expose(&tree[v]);
		tree[v].value = f(tree[v].value);
		recalc(&tree[v]);
	}
	void update(const size_type u, const size_type v, const operator_type &data) {
		assert(u < size());
		assert(v < size());
		reroot(u);
		expose(&tree[v]);
		tree[v].assign(data);
	}
	value_type path(const size_type u, const size_type v) {
		assert(u < size());
		assert(v < size());
		reroot(u);
		expose(&tree[v]);
		return tree[v].sum;
	}
	size_type size() const noexcept { return tree.size(); }
	bool empty() const noexcept { return tree.empty(); }
};

#include <algorithm>
struct Ass {
	int a;
	bool f;
	Ass() : f(1) {}
	Ass(int a) : a(a), f(0) {}
	Ass operator+(const Ass &o) const { return o.f ? *this : o; }
};
struct Line {
	int all, l, r, max, siz;
	bool f;
	Line() : f(1) {}
	Line(int all, int l, int r, int max, int siz, bool f = 0)
		: all(all), l(l), r(r), max(max), siz(siz), f(f) {}
	Line operator~() const { return Line(all, r, l, max, siz, f); }
	Line operator+(const Line &o) const {
		if (f)
			return o;
		if (o.f)
			return *this;
		return Line(all + o.all, std::max(l, o.l > 0 ? all + o.l : all),
			std::max(o.r, r > 0 ? r + o.all : o.all),
			std::max(std::max(max, o.max), r + o.l), siz + o.siz);
	}
};
struct hoge {
	Line operator()(const Line &x, const Ass &y) const {
		if (y.f || x.f)
			return x;
		if (y.a > 0)
			return Line(y.a * x.siz, y.a * x.siz, y.a * x.siz, y.a * x.siz, x.siz);
		else
			return Line(y.a * x.siz, y.a, y.a, y.a, x.siz);
	}
};

#include <cstdio>
#include <vector>
int main(void) {
	int nn, q;
	scanf("%d %d", &nn, &q);
	const int n = nn;
	std::vector<Line> d;
	int w;
	for (int i = 0; i < n; ++i) {
		scanf("%d", &w);
		d.emplace_back(w, w, w, w, 1);
	}
	LinkCutTree<Line, Ass, hoge> T(d);
	int s, e;
	for (int i = 1; i < n; ++i) {
		scanf("%d %d", &s, &e);
		T.link(s - 1, e - 1);
	}
	int t, a, b;
	Ass c(0);
	while (q--) {
		scanf("%d %d %d %d", &t, &a, &b, &c.a);
		if (t == 1)
			T.update(a - 1, b - 1, c);
		else
			printf("%d\n", T.path(a - 1, b - 1).max);
	}
	return 0;
}