#define NDEBUG

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <tuple>
#include <cassert>

using namespace std;
  
typedef long long ll;
 
struct LCTree {
    typedef int D;
    static const int INF = 1LL<<25;
    static const int DF = 1LL<<25;
    struct Node;
    typedef Node* NP;
    static Node last_d;
    static NP last;
    struct Node {
        NP p, l, r;
        int sz;
        int v, sm, lz;
        int lsm, rsm, ma, mv;
        bool rev;
        Node(D v) :p(NULL), l(last), r(last), sz(1),
            v(v), sm(v), lz(DF), rev(false),
            lsm(max(v, 0)), rsm(max(v, 0)), ma(max(v, 0)), mv(v) {}
        Node(string s) : l(NULL), r(NULL), sz(0), v(-INF), mv(-INF) {}
        inline int pos() {
            if (p) {
                if (p->l == this) return -1;
                if (p->r == this) return 1;
            }
            return 0;
        }
        void rot() {
            NP q = p, qq = q->p;
            int qp = q->pos();
            if (q->l == this) {
                q->l = r; r->p = q;
                r = q; q->p = this;
            } else {
                q->r = l; l->p = q;
                l = q; q->p = this;
            }
            q->update(); update();
            p = qq;
            if (!qp) return;
            if (qp == -1) {
                qq->l = this;
            } else {
                qq->r = this;
            }
            qq->update();
        }
        void splay() {
            assert(this != last);
            supush();
            int ps;
            while ((ps = pos())) {
                int pps = p->pos();
                int u = ps*p->pos();
                if (!pps) {
                    rot();
                } else if (ps == pps) {
                    p->rot(); rot();
                } else {
                    rot(); rot();
                }
            }
        }
        void expose() {
            assert(this != last);
            NP u = this;
            do {
                u->splay();
            } while ((u = u->p));
            u = last;
            u->p = this;
            do {
                u->p->r = u;
                u->p->update();
                u = u->p;
            } while (u->p);
            splay();
        }
        void push() {
            if (rev) {
                if (l->sz) {
                    l->revdata();
                }
                if (r->sz) {
                    r->revdata();
                }
                rev = false;
            }
 
            if (lz != DF) {
                if (l->sz) {
                    l->lzdata(lz);
                }
                if (r->sz) {
                    r->lzdata(lz);
                }
                lz = DF;
            }
        }
        void supush() {
            if (pos()) {
                p->supush();
            }
            push();
        }
        void revdata() {
            swap(l, r);
            swap(lsm, rsm);
            rev ^= true;
        }
        void lzdata(D d) {
            v = d;
            sm = sz*d;
            lsm = rsm = ma = max(0, sm);
            mv = d;
            lz = d;
        }
        NP update() {
            assert(this != last);
            sz = 1+l->sz+r->sz;
            sm = v + l->sm + r->sm;
            lsm = max(l->lsm, l->sm+v+r->lsm);
            rsm = max(r->rsm, r->sm+v+l->rsm);
            ma = max(l->ma, r->ma);
            ma = max(ma, l->rsm+v+r->lsm);
            mv = max(l->mv, r->mv);
            mv = max(mv, v);
            return this;
        }
    } *n;
    LCTree() : n(last) {}
    LCTree(NP n) : n(n) {}
    LCTree(D id, D d) : n(new Node(d)) {}
    int sz() {
        return n->sz;
    }
    void event() {
        n->expose();
        n->revdata();
    }
    void link(LCTree r) {
        event();
        r.n->expose();
        n->p = r.n;
    }
    void set(int x) {
        n->expose();
        n->lzdata(x);
    }
    int get() {
        n->expose();
        if (n->mv < 0) return n->mv;
        return n->ma;
    }
};
LCTree::Node LCTree::last_d = LCTree::Node("last");
LCTree::NP LCTree::last = &last_d;
 
  
const int MN = 201000;
LCTree tr[MN];
int main() {
    int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 0; i < n; i++) {
        int w;
        scanf("%d", &w);
        tr[i] = LCTree(i, w);
    }
    for (int i = 0; i < n-1; i++) {
        int s, e;
        scanf("%d %d", &s, &e); s--; e--;
        tr[s].link(tr[e]);
    }
    for (int i = 0; i < q; i++) {
        int t, a, b, c;
        scanf("%d %d %d %d", &t, &a, &b, &c); a--; b--;
        if (t == 1) {
            tr[a].event();
            tr[b].set(c);
        } else {
            tr[a].event();
            printf("%d\n", tr[b].get());
        }
    }
}

Measured memory_bytes: 18396