// implment 1h10min
// debug1 14min
// debug2 7min
// implement2 13min
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

struct Node {
  int ans;
  int left;
  int right;
  int all;
  Node() {;}
  Node(int v) : ans(v), left(v), right(v), all(v) {;}
};

inline Node Merge(Node left, Node right) {
  Node ret;
  ret.left = max(left.left, left.all + right.left);
  ret.right = max(right.right, right.all + left.right);
  ret.all = left.all + right.all;
  ret.ans = max(left.right + right.left, max(left.ans, right.ans));
  return ret;
}

struct SegmentTree {
  //static const int MAX_DEPTH = 17;
  //static const int SIZE = 1 << (MAX_DEPTH + 1);  // 2^18 = 262144
  int MAX_DEPTH;
  int SIZE;
  vector<bool> updated;
  vector<Node> data;

  SegmentTree() {;}
  SegmentTree(int size) {
    SIZE = 1;
    MAX_DEPTH = 0;
    while (SIZE < size) {
      MAX_DEPTH++;
      SIZE <<= 1;
    }
    SIZE <<= 1;
    updated = vector<bool>(SIZE, false);
    data = vector<Node>(SIZE, Node(-100000));
  }
  void set(int left, int right, Node v) {
    assert(left <= right);
    return in_set(v, 0, 1, left, right);
  }
  Node get(int left, int right) {
    assert(left <= right);
    return in_get(0, 1, left, right);
  }

private:
  void Divide(int node) {
    if (!updated[node] || node >= (1 << MAX_DEPTH)) { return; }
    updated[node] = false;
    updated[node * 2] = true;
    updated[node * 2 + 1] = true;
    if (data[node].all < 0) {
      data[node * 2] = data[node];
      data[node * 2].all = data[node].all / 2;
    } else {
      data[node * 2] = Node(data[node].all / 2);
    }
    data[node * 2 + 1] = data[node * 2];
  }

  void in_set(Node v, int depth, int node, int left, int right) {
    int width = 1 << (MAX_DEPTH - depth);
    int index = node - (1 << depth);
    int node_left = index * width;
    int node_mid = node_left + (width >> 1);
    Divide(node);
    if (right - left + 1 == width && left == node_left) {
      updated[node] = true;
      if (v.all < 0) {
        data[node] = Node(v.all);
        data[node].all = v.all * width;
      } else {
        data[node] = Node(v.all * width);
      }
    } else {
      if (right < node_mid) {
        in_set(v, depth + 1, node * 2, left, right);
      } else if (left >= node_mid) {
        in_set(v, depth + 1, node * 2 + 1, left, right);
      } else {
        in_set(v, depth + 1, node * 2, left, node_mid - 1);
        in_set(v, depth + 1, node * 2 + 1, node_mid, right);
      }
      data[node] = Merge(data[node * 2], data[node * 2 + 1]);
    }
  }

  Node in_get(int depth, int node, int left, int right) {
    int width = 1 << (MAX_DEPTH - depth);
    int index = node - (1 << depth);
    int node_left = index * width;
    int node_mid = node_left + (width >> 1);
    Divide(node);
    if (right - left + 1 == width && left == node_left) {
      return data[node];
    } else if (right < node_mid) {
      return in_get(depth + 1, node * 2, left, right);
    } else if (left >= node_mid) {
      return in_get(depth + 1, node * 2 + 1, left, right);
    }
    return Merge(in_get(depth + 1, node * 2, left, node_mid - 1), in_get(depth + 1, node * 2 + 1, node_mid, right));
  }
};

typedef int Weight;
struct Edge {
  int src;
  int dest;
  Weight weight;
  Edge(int src, int dest, Weight weight) : src(src), dest(dest), weight(weight) {;}
  bool operator<(const Edge &rhs) const {
    if (weight != rhs.weight) { return weight > rhs.weight; }
    if (src != rhs.src) { return src < rhs.src; }
    return dest < rhs.dest;
  }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void PrintMatrix(const Matrix &matrix) {
  for (int y = 0; y < (int)matrix.size(); y++) {
    for (int x = 0; x < (int)matrix[y].size(); x++) {
      printf("%d ", matrix[y][x]);
    }
    puts("");
  }
}

struct HeavyLightDecomposition {
  struct Chain {
    int depth;
    pair<int, int> parent; // chain number, index
    vector<pair<int, int> > child; // child chain number, parent index
    vector<int> mapfrom;
    SegmentTree stree;
  };
  Graph baseG;
  vector<Chain> chains;
  vector<pair<int, int> > mapto;
  vector<vector<int> > mapfrom;

  HeavyLightDecomposition() {;}
  HeavyLightDecomposition(const Graph &g) {
    baseG = g;
    Init();
  }
  void Init() {
    const int n = baseG.size();
    mapto = vector<pair<int, int> >(n, make_pair(-1, -1));
    mapfrom.clear();
    vector<int> size(n, 0);
    int start = -1;
    for (int i = 0; i < n; i++) {
      if (baseG[i].size() <= 1) {
        start = i;
        break;
      }
    }
    assert(start != -1);
    SizeCheckBfs(start, size);
    Decomposition(start, start, 0, 0, 0, size);
  }

  int Depth(int t) {
    return chains[mapto[t].first].depth;
  }
  bool SameChain(int f, int t) {
    return mapto[f].first == mapto[t].first;
  }

private:
  int Decomposition(int from, int parent, int depth, int pnumber, int pindex, vector<int> &size) {
    const int c = chains.size();
    chains.push_back(Chain());
    chains[c].depth = depth;
    chains[c].parent = make_pair(pnumber, pindex);
    vector<int> seq;
    Bfs(from, parent, seq, size);
    for (int i = 0; i < (int)seq.size(); i++) {
      mapto[seq[i]] = make_pair(c, i);
      chains[c].mapfrom.push_back(seq[i]);
    }
    chains[c].stree = SegmentTree(seq.size());
    for (int i = 0; i < (int)seq.size(); i++) {
      for (Edges::const_iterator it = baseG[seq[i]].begin(); it != baseG[seq[i]].end(); it++) {
        if (mapto[it->dest].first != -1) { continue; }
        int nc = Decomposition(it->dest, seq[i], depth + 1, c, i, size);
        chains[c].child.push_back(make_pair(nc, i));
      }
    }
    return c;
  }
  void SizeCheckBfs(int start, vector<int> &size) {
    const int n = baseG.size();
    queue<pair<int, int> > que;
    que.push(make_pair(start, start));
    int cnt = 0;
    vector<int> order(n, -1);
    while (!que.empty()) {
      int from = que.front().first;
      int parent = que.front().second;
      que.pop();
      order[cnt++] = from;
      for (Edges::const_iterator it = baseG[from].begin(); it != baseG[from].end(); it++) {
        if (it->dest == parent) { continue; }
        que.push(make_pair(it->dest, from));
      }
    }
    assert(cnt == n);
    reverse(order.begin(), order.end());
    REP(i, n) {
      int from = order[i];
      size[from] = 1;
      for (Edges::const_iterator it = baseG[from].begin(); it != baseG[from].end(); it++) {
        size[from] += size[it->dest];
      }
    }
  }
  void Bfs(int from, int parent, vector<int> &seq, const vector<int> &size) {
    while (true) {
      seq.push_back(from);
      int best = -1;
      int next = -1;
      for (Edges::const_iterator it = baseG[from].begin(); it != baseG[from].end(); it++) {
        if (it->dest == parent) { continue; }
        if (best < size[it->dest]) {
          best = size[it->dest];
          next = it->dest;
        }
      }
      if (next == -1) { break; }
      parent = from;
      from = next;
    }
  }
};

int n, q;
int w[200010];
Graph baseG;
HeavyLightDecomposition chains;

void Change(int t, int w) {
  int c = chains.mapto[t].first;
  int index = chains.mapto[t].second;
  chains.chains[c].stree.set(index, index, w);
}

int Query(int type, int f, int t, int w) {
  Node fNode(-1000000);
  Node tNode(-1000000);
  while (!chains.SameChain(f, t)) {
    if (chains.Depth(f) < chains.Depth(t)) {
      swap(f, t);
      swap(fNode, tNode);
    }
    int c = chains.mapto[f].first;
    int index = chains.mapto[f].second;
    if (type == 1) {
      chains.chains[c].stree.set(0, index, Node(w));
    } else {
      Node temp = chains.chains[c].stree.get(0, index);
      fNode = Merge(temp, fNode);
    }
    int nc = chains.chains[c].parent.first;
    int nindex = chains.chains[c].parent.second;
    f = chains.chains[nc].mapfrom[nindex];
  }
  int c = chains.mapto[f].first;
  int index1 = chains.mapto[f].second;
  int index2 = chains.mapto[t].second;
  if (index1 > index2) {
    swap(index1, index2);
    swap(f, t);
    swap(fNode, tNode);
  }
  if (type == 1) {
    chains.chains[c].stree.set(index1, index2, w);
  } else {
    Node center = chains.chains[c].stree.get(index1, index2);
    center = Merge(center, tNode);
    swap(fNode.left, fNode.right);
    center = Merge(fNode, center);
    return center.ans;
  }
  return 0;
}

int main() {
  while (scanf("%d %d", &n, &q) > 0) {
    baseG = Graph(n);
    REP(i, n) {
      int v = scanf("%d", &w[i]);
      assert(v == 1);
    }
    REP(i, n - 1) {
      int s, e;
      int v = scanf("%d %d", &s, &e);
      assert(v == 2);
      s--; e--;
      baseG[s].push_back(Edge(s, e, 0));
      baseG[e].push_back(Edge(e, s, 0));
    }
    chains = HeavyLightDecomposition(baseG);
    REP(i, n) {
      Change(i, w[i]);
    }
    REP(i, q) {
      int t, a, b, c;
      int v = scanf("%d %d %d %d", &t, &a, &b, &c);
      assert(v == 4);
      a--; b--;
      int ans = Query(t, a, b, c);
      if (t == 2) {
        printf("%d\n", ans);
      }
    }
  }
}

Measured memory_bytes: 145424