using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static System.Console;
using static System.Math;

struct P
{
    public int m, l, r, s, z;
}
public struct Pair<T>
{
    public T l, r;
}
class Program
{
    static P F(P l, P r)
    {
        if (l.z == int.MaxValue) return r;
        if (r.z == int.MaxValue) return l;
        return new P { m = Max(Max(l.m, r.m), l.r + r.l), l = Max(l.l, l.s + r.l), r = Max(r.r, l.r + r.s), s = l.s + r.s, z = l.z + r.z };
    }

    static P D(P r, P l)
    {
        if (l.z == int.MaxValue) return r;
        if (r.z == int.MaxValue) return l;
        return new P { m = Max(Max(l.m, r.m), l.r + r.l), l = Max(l.l, l.s + r.l), r = Max(r.r, l.r + r.s), s = l.s + r.s, z = l.z + r.z };
    }

    static P G(P l, int r)
    {
        if (r == ei) return l;
        var x = r * l.z;
        var y = Max(x, r);
        return l.z == 1 ? new P { m = x, l = x, r = x, s = x, z = 1 } : new P { m = y, l = y, r = y, s = r * l.z, z = l.z };
    }

    static int H(int l, int r)
    {
        return r == ei ? l : r;
    }

    static P ti => new P { m = 0, l = 0, r = 0, s = 0, z = int.MaxValue };
    static int ei => int.MinValue;


    static void Main()
    {
        SetOut(new System.IO.StreamWriter(OpenStandardOutput()) { AutoFlush = false });

        var n = FastIO.Int();
        var q = FastIO.Int();
        var w = new int[n];
        for (int i = 0; i < n; i++)
        {
            w[i] = FastIO.Int();
        }
        var g = new List<int>[n];
        for (int i = 0; i < g.Length; i++)
        {
            g[i] = new List<int>();
        }
        for (int i = 0; i < n - 1; i++)
        {
            var s = FastIO.Int() - 1;
            var e = FastIO.Int() - 1;
            g[s].Add(e);
            g[e].Add(s);
        }
        var hld = new HeavyLightDecompsition(g, 0);
        var y = new P[n];
        for (int i = 0; i < y.Length; i++)
        {
            var x = w[i];
            y[i] = new P { m = x, l = x, r = x, s = x, z = 1 };
        }
        var a1 = new int[n];
        Array.Copy(hld.vid, 0, a1, 0, n);
        Array.Sort(a1, y);
        var st = new SegmentTree<P, int>(y, F, G, H, ti, ei);
        var dl = new SegmentTree<P, int>(y, D, G, H, ti, ei);
        for (int i = 0; i < q; i++)
        {
            var t = FastIO.Int();
            var a = FastIO.Int() - 1;
            var b = FastIO.Int() - 1;
            var c = FastIO.Int();
            if (t == 1)
            {
                var h = hld.Path(a, b);
                foreach (var o in h.l)
                {
                    var l = o.l;
                    var r = o.r;
                    st.Update(l, r, c);
                    dl.Update(l, r, c);
                }
                foreach (var o in h.r)
                {

                    var l = o.l;
                    var r = o.r;
                    st.Update(l, r, c);
                    dl.Update(l, r, c);
                }
            }
            else
            {
                var h = hld.Path(a, b);
                var lv = ti;
                foreach (var o in h.l)
                {

                    var l = o.l;
                    var r = o.r;
                    lv = F(lv, dl.Query(l, r));
                }
                var rv = ti;
                foreach (var o in h.r)
                {

                    var l = o.l;
                    var r = o.r;
                    rv = D(rv, st.Query(l, r));
                }
                WriteLine(F(lv, rv).m);
            }
        }

        Out.Flush();
    }
}

public class HeavyLightDecompsition
{
    public int[] size, vid, par, head, inv, depth;

    public HeavyLightDecompsition(List<int>[] tree, int root)
    {
        var len = tree.Length;
        size = new int[len];
        vid = new int[len];
        par = new int[len];
        head = new int[len];
        inv = new int[len];
        depth = new int[len];

        depth[root] = 0;
        tree[root].Add(-1);
        DFSS(root, -1, tree);
        var k = 0;
        head[root] = root;
        DFSD(root, -1, ref k, tree);
    }

    void DFSS(int v, int p, List<int>[] tree)
    {
        par[v] = p;
        size[v] = 1;
        for (int i = 0; i < tree[v].Count - 1; i++)
        {
            var u = tree[v][i];
            if (u == p)
            {
                u = tree[v][i] = tree[v][tree[v].Count - 1];
                tree[v][tree[v].Count - 1] = p;
            }
            depth[u] = depth[v] + 1;
            DFSS(u, v, tree);
            size[v] += size[u];
            var h = tree[v][0];
            if (size[h] < size[u])
            {
                tree[v][0] = u;
                tree[v][i] = h;
            }
        }
    }

    void DFSD(int v, int p, ref int k, List<int>[] tree)
    {
        vid[v] = k;
        inv[k++] = v;
        for (int i = 0; i < tree[v].Count - 1; i++)
        {
            var u = tree[v][i];
            if (u == p) continue;
            head[u] = u == tree[v][0] ? head[v] : u;
            DFSD(u, v, ref k, tree);
        }
    }

    void Swap<T>(ref T l, ref T r)
    {
        var t = l;
        l = r;
        r = t;
    }

    public int Distance(int u, int v)
    {
        return depth[u] + depth[v] - 2 * depth[LCA(u, v)];
    }

    public int LCA(int u, int v)
    {
        while (true)
        {
            if (vid[u] > vid[v]) Swap(ref u, ref v);
            if (head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }

    public int LA(int v, int d)
    {
        while (true)
        {
            if (depth[head[v]] <= d) return inv[vid[v] - (depth[v] - d)];
            v = par[head[v]];
        }
    }

    public Pair<List<Pair<int>>> Path(int u, int v)
    {
        var b = vid[u] < vid[v];
        if (head[u] == head[v]) return b ? new Pair<List<Pair<int>>> { l = new List<Pair<int>>(), r = new List<Pair<int>> { new Pair<int> { l = vid[u], r = vid[v] + 1 } } } : new Pair<List<Pair<int>>> { l = new List<Pair<int>> { new Pair<int> { l = vid[v], r = vid[u] + 1 } }, r = new List<Pair<int>>() };

        var lca = LCA(u, v);
        var dep = depth[lca];
        var l = new List<Pair<int>>();
        var r = new List<Pair<int>>();
        if (b)
        {
            while (depth[u] >= dep)
            {
                l.Add(new Pair<int> { l = Max(vid[head[u]], vid[lca]), r = vid[u] + 1 });
                u = par[head[u]];
                if (u == -1) break;
            }
            while (depth[v] > dep)
            {
                r.Add(new Pair<int> { l = Max(vid[head[v]], vid[lca] + 1), r = vid[v] + 1 });
                v = par[head[v]];
                if (v == -1) break;
            }
        }
        else
        {
            while (depth[u] > dep)
            {
                l.Add(new Pair<int> { l = Max(vid[head[u]], vid[lca] + 1), r = vid[u] + 1 });
                u = par[head[u]];
                if (u == -1) break;
            }
            while (depth[v] >= dep)
            {
                r.Add(new Pair<int> { l = Max(vid[head[v]], vid[lca]), r = vid[v] + 1 });
                v = par[head[v]];
                if (v == -1) break;
            }
        }
        return new Pair<List<Pair<int>>> { l = l, r = r };
    }

}

public static class FastIO
{
    static System.IO.Stream str = System.Console.OpenStandardInput();
    const int size = 1024;
    static byte[] buffer = new byte[size];
    static int ptr;
    static int len;

    static byte Read()
    {
        if (ptr == len)
        {
            len = str.Read(buffer, 0, size);
            if (len == 0) return 0;
            ptr = 0;
        }
        return buffer[ptr++];
    }

    public static int Int()
    {
        var c = Read();
        while (c < 0x21)
        {
            c = Read();
        }
        var n = false;
        if (c == '-')
        {
            n = true;
            c = Read();
        }
        var ret = 0;
        while (c > 0x20)
        {
            ret = ret * 10 + c - '0';
            c = Read();
        }
        return n ? -ret : ret;
    }

    public static long Long()
    {
        var c = Read();
        while (c < 0x21)
        {
            c = Read();
        }
        var n = false;
        if (c == '-')
        {
            n = true;
            c = Read();
        }
        var ret = 0L;
        while (c > 0x20)
        {
            ret = ret * 10 + c - '0';
            c = Read();
        }
        return n ? -ret : ret;
    }
}

public class SegmentTree<T, E>// where E : IEquatable<E>
{
    T[] buffer;
    E[] lazy;
    Func<T, T, T> F;
    Func<T, E, T> G;
    Func<E, E, E> H;
    T TI;
    E EI;
    int N;
    public int Length => N;
    int height;

    public SegmentTree(int length, Func<T, T, T> f, Func<T, E, T> g, Func<E, E, E> h, T ti, E ei)
    {
        F = f;
        G = g;
        H = h;
        TI = ti;
        EI = ei;

        N = length;
        height = 1;//!log2
        while (1 << height < length) height++;

        buffer = new T[N * 2];
        for (int i = 0; i < buffer.Length; i++) buffer[i] = TI;//Array.Fill

        lazy = new E[N * 2];
        for (int i = 0; i < lazy.Length; i++) lazy[i] = EI;//Array.Fill
    }

    public SegmentTree(T[] init, Func<T, T, T> f, Func<T, E, T> g, Func<E, E, E> h, T ti, E ei)
    {
        F = f;
        G = g;
        H = h;
        TI = ti;
        EI = ei;

        N = init.Length;
        height = 1;//!log2
        while (1 << height < N) height++;

        buffer = new T[N * 2];
        Array.Copy(init, 0, buffer, N, init.Length);
        for (int i = N + init.Length; i < buffer.Length; i++) buffer[i] = TI;
        for (int i = N - 1; i != 0; i--) buffer[i] = F(buffer[i * 2 + 0], buffer[i * 2 + 1]);

        lazy = new E[N * 2];
        for (int i = 0; i < lazy.Length; i++) lazy[i] = EI;//Array.Fill
    }

    T Reflect(int k)
    {
        //if (lazy[k].Equals(EI)) return buffer[k];//Type Classes!//lazy[k] == EI
        return G(buffer[k], lazy[k]);
    }

    void Propagate(int k)
    {
        //if (lazy[k].Equals(EI)) return;//Type Classes!//lazy[k] == EI
        lazy[k * 2 + 0] = H(lazy[k * 2 + 0], lazy[k]);
        lazy[k * 2 + 1] = H(lazy[k * 2 + 1], lazy[k]);
        buffer[k] = Reflect(k);
        lazy[k] = EI;
    }

    void Thrust(int k)
    {
        for (int i = height; i != 0; i--) Propagate(k >> i);
    }

    void Recalc(int k)
    {
        while ((k >>= 1) != 0) buffer[k] = F(Reflect(k * 2 + 0), Reflect(k * 2 + 1));
    }

    public void Update(int l, int r, E v)
    {
        var a = l += N;
        var b = (r += N) - 1;
        Thrust(a);
        Thrust(b);
        for (; l < r; l >>= 1, r >>= 1)
        {
            if ((l & 1) != 0) { lazy[l] = H(lazy[l], v); l++; }
            if ((r & 1) != 0) { --r; lazy[r] = H(lazy[r], v); }
        }
        Recalc(a);
        Recalc(b);
    }

    public T Query(int l, int r)
    {
        Thrust(l += N);
        Thrust(r += N - 1);
        var vl = TI;
        var vr = TI;
        for (r++; l < r; l >>= 1, r >>= 1)
        {
            if ((l & 1) != 0) vl = F(vl, Reflect(l++));
            if ((r & 1) != 0) vr = F(Reflect(--r), vr);
        }
        return F(vl, vr);
    }

    public void Set(int i, T v)
    {
        var k = i + N;
        Thrust(k);
        buffer[k] = v;
        lazy[k] = EI;
        Recalc(k);
    }

    public T Get(int i)
    {
        var k = i + N;
        Thrust(k);
        return Reflect(k);
    }
}



Measured memory_bytes: 83848