#include <bits/stdc++.h>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <sstream>
#include <set>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstdlib>

#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define iter(a) __typeof(a.begin())
#define FOR(it,a) for(iter(a)it=a.begin();it!=a.end();++it)
#define F first
#define S second
#define SZ(a) (int)((a).size())
#define sz(a) SZ(a)
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define ALL(a) (a).begin(),(a).end()
using namespace std;

typedef long long ll;
typedef pair<int,int> PI;
typedef unsigned long long ull;

#ifdef ONLINE_JUDGE
#define PR(...) (void(0))
#else
#define PR(...) do{cerr << "line : " << __LINE__ << endl; pr(#__VA_ARGS__, __VA_ARGS__);}while(0)
template<class T>
void pr(const string& name, T t){
  cerr << name << ": " << t << endl;
}
template<typename T, typename ... Types>
void pr(const string& names, T t, Types ... rest) {
  auto comma_pos = names.find(',');
  cerr << names.substr(0, comma_pos) << ": " << t << ", ";
  auto next_name_pos = names.find_first_not_of(" \t\n", comma_pos + 1);
  pr(string(names, next_name_pos), rest ...);
}
#endif

template<class T,class U> ostream& operator<< (ostream& o, const pair<T,U>& v){return o << "(" << v.F << ", " << v.S << ")";}
template<class T> ostream& operator<< (ostream& o, const vector<T>& v){o << "{";rep(i,SZ(v)) o << (i?", ":"") << v[i];return o << "}";}
template<class T,class U> ostream& operator<< (ostream& o, const map<T,U>& v){o << "{";for(const auto& e : v) o << e << ", ";return o << "}";}
template<class T> string to_s(const T& v){ostringstream is;is << v;return is.str();}
//                 <  ^  >  V
const int dx[] = { 0,-1, 0, 1};
const int dy[] = {-1, 0, 1, 0};
#define endl '\n'


namespace HeavyLight{
  /*
    verify
    * [Submission for TRIPS](http://www.codechef.com/viewsolution/5083769)
    * [Submission for white-falcon-and-tree](https://www.hackerrank.com/contests/w12/challenges/white-falcon-and-tree/submissions/code/2445498)
    * [Submission for E. Misha and LCP on Tree](http://codeforces.ru/contest/504/submission/9411256)
    * [Submission for Tavas on the Path](http://codeforces.com/contest/536/submission/10727621)
    * http://www.spoj.com/submit/QTREE2/id=14101324
    trap
    * getseg -> [a, b] not [a, b)
    * merge
    * seg size
    * getseg(s == t) -> exception exist
    */
  
  const int MAX_N = 2e5+10;
  vector<int> G[MAX_N];
  
  pair<int, int> upsegpos[MAX_N];
  pair<int, int> downsegpos[MAX_N];
  

  struct data{
    ll lsum;    
    ll msum;
    ll rsum;    
    ll all;
    bool empty;
    data(ll lsum_ = 0, ll msum_ = 0, ll rsum_ = 0, ll all_ = 0,
         bool empty_ = false):
      lsum(lsum_), msum(msum_), rsum(rsum_), all(all_), empty(empty_){
    }
    
    data operator+(const data& r){
      if(r.empty) return *this;
      if(empty) return r;
      data ret(lsum, rsum + r.lsum, r.rsum, all + r.all);
      ret.lsum = max(ret.lsum, all + r.lsum);
      ret.rsum = max(ret.rsum, rsum + r.all);
      ret.msum = max(ret.msum, r.msum);
      ret.msum = max(ret.msum, msum);
      ret.msum = max(ret.msum, lsum);
      ret.msum = max(ret.msum, r.rsum);
      ret.msum = max(ret.msum, ret.all);
      // PR(rsum, lsum, msum, all);
      // PR(r.rsum, r.lsum, r.msum, r.all);
      // PR(ret.rsum, ret.lsum, ret.msum, ret.all);
      return ret;
    }
  };
  
  struct Segtree{
    vector<int> seg;
    vector<data> val;
    vector<PI> lazy;
    void init(){
      int n = seg.size();
      val.resize(n * 4);
      lazy.resize(n * 4);
    }
    
    void lazyupdate(int k, int len){
      if(lazy[k].F){
        if(len > 1){
          lazy[k * 2 + 1] = lazy[k];
          lazy[k * 2 + 2] = lazy[k];
        }
        lazy[k].F = false;
        ll cval = max<ll>(lazy[k].S, lazy[k].S * (ll)len);
        val[k].rsum = cval;
        val[k].lsum = cval;
        val[k].msum = cval;
        val[k].all = lazy[k].S * (ll)len;
      }
    }
    
    data query(int cl, int cr, int ql, int qr, int k){
      lazyupdate(k, cr - cl);
      if(ql <= cl && cr <= qr) return val[k];
      if(qr <= cl || cr <= ql){
        const ll minf = -(1LL << 60LL);
        return data(minf, minf, minf, minf, true);
      }
      int mid = (cl + cr) / 2;
      return query(cl, mid, ql, qr, k * 2 + 1) + query(mid, cr, ql, qr, k * 2 + 2);
    }
    
    data query(int a, int b){
      return query(0, SZ(seg), a, b, 0);
    }
    
    data update(int cl, int cr, int ql, int qr, int k, int c){
      //PR(cl, cr, ql, qr, k, c, SZ(lazy));
      lazyupdate(k, cr - cl);
      if(ql <= cl && cr <=  qr){
        lazy[k] = mp(1, c);
        lazyupdate(k, cr - cl);
      }else if(qr <= cl || cr <= ql){
      }else{
        int mid = (cl + cr) / 2;
        val[k] = update(cl, mid, ql, qr, k * 2 + 1, c) + update(mid, cr, ql, qr, k * 2 + 2, c);
      }
      return val[k];
    }
    
    data update(int a, int b, int c){
      return update(0, SZ(seg), a, b, 0, c);
    }
    
  };
  
  Segtree segs[MAX_N*2];
  int segscnt;
  
  int subwe[MAX_N];
  int depth[MAX_N];
  int subtdfs(int cv = 0, int p = -1, int d = 0){
    subwe[cv] = 1;
    depth[cv] = d;
    for(auto e : G[cv])
      if(e != p)
        subwe[cv] += subtdfs(e, cv, d + 1);
    return subwe[cv];
  }
 
  int pnodeseg[MAX_N];
  void makeheavy(int cv = 0, int p = -1){
    vector<int> seg;
    int segp = p;
    while(true){
      auto ne = mp(mp(-1,0),0);
      for(auto e : G[cv])
        if(e != p)
          ne = max(mp(mp(subwe[e],e),e),ne);
      pnodeseg[cv] =  segp;
      seg.push_back(cv);
      if(ne.F.F == -1)
        break;
    
      int np = cv;
      int ncv = ne.F.S;
      for(auto e : G[cv]){
        if(e == p) continue;
        if(e != ne.F.S)
          makeheavy(e,cv);
      }
      p = np;
      cv = ncv;
    }
    
    for(int i = 0; i < SZ(seg); ++i)
      downsegpos[seg[i]] = mp(segscnt,i);
    segs[segscnt++].seg = seg;
    segs[segscnt-1].init();
    
    reverse(ALL(seg));
    for(int i = 0; i < SZ(seg); ++i)
      upsegpos[seg[i]] = mp(segscnt,i);
    
    segs[segscnt++].seg = seg;
    segs[segscnt-1].init();
  }
  
  
  inline vector<pair<int,pair<int, int>> > getseg(int s, int t){
    if(s==t){
      vector<pair<int,pair<int, int>> > ret;
      ret.pb(mp(upsegpos[s].F,mp(upsegpos[s].S,upsegpos[s].S)));
      ret.pb(mp(downsegpos[s].F,mp(downsegpos[s].S,downsegpos[s].S)));
      return ret;
    }
  
    static vector<pair<int,pair<int, int> > > sret,tret;
    sret.clear();
    tret.clear();
    int ss = s;
    int tt = t;
    while(s != t){
      int ps = segs[upsegpos[s].F].seg.back();
      int pt = segs[downsegpos[t].F].seg[0];
      
      if(ps == pt){
        if(depth[s] < depth[t]){
          tret.push_back(mp(downsegpos[t].F,mp(downsegpos[s].S,downsegpos[t].S)));
        }else{
          sret.push_back(mp(upsegpos[s].F,mp(upsegpos[s].S,upsegpos[t].S)));
        }
        break;
      }
    
      if(depth[ps] < depth[pt]){
        tret.push_back(mp(downsegpos[t].F,mp(0,downsegpos[t].S)));
        t = pnodeseg[t];
      }else{
        sret.push_back(mp(upsegpos[s].F,mp(upsegpos[s].S,segs[upsegpos[s].F].seg.size()-1)));
        s = pnodeseg[s];
      }
      if(s == t){
        if(ss < tt) sret.pb(mp(downsegpos[t].F,mp(downsegpos[t].S,downsegpos[t].S)));
        else sret.pb(mp(upsegpos[t].F,mp(upsegpos[t].S,upsegpos[t].S)));
      }
    }
  
    for(int i = SZ(tret)-1; i >= 0; --i)
      sret.pb(tret[i]);
    return sret;
  }
}

#define BEGIN_STACK_EXTEND(size) void * stack_extend_memory_ = malloc(size);void * stack_extend_origin_memory_;char * stack_extend_dummy_memory_ = (char*)alloca((1+(int)(((long long)stack_extend_memory_)&127))*16);*stack_extend_dummy_memory_ = 0;asm volatile("mov %%rsp, %%rbx\nmov %%rax, %%rsp":"=b"(stack_extend_origin_memory_):"a"((char*)stack_extend_memory_+(size)-1024));

#define END_STACK_EXTEND asm volatile("mov %%rax, %%rsp"::"a"(stack_extend_origin_memory_));free(stack_extend_memory_);

int main(int argc, char *argv[])
{
BEGIN_STACK_EXTEND(1 << 24);
  ios::sync_with_stdio(0);
  cin.tie(0);
  using namespace HeavyLight;

  int n, q;
  cin >> n >> q;
  vector<int> we(n);
  rep(i, n) cin >> we[i];
  rep(i, n-1){
    int a, b;
    cin >> a >> b;
    --a, --b;
    G[a].pb(b);
    G[b].pb(a);
  }
  subtdfs();
  makeheavy();
  
  rep(i, n){
    //PR(i);
    for(auto e : getseg(i, i)){
      auto ret = segs[e.F].update(e.S.F, e.S.S + 1, we[i]);
      //PR(i, e, ret.lsum, ret.rsum, ret.msum, ret.all);
    }
  }

  rep(iiq, q){
    int t, a, b, c;
    cin >> t >> a >> b >> c;
    //PR(t, a, b, c);
    --a, --b;
    if(t == 1){
      rep(i, 1 + (a != b)){
        for(auto e : getseg(a, b)){
          segs[e.F].update(e.S.F, e.S.S + 1, c);
        }
        swap(a, b);
      }
      //PR("upd");
      continue;
    }

    ll minf = -(1LL << 60LL);
    data ans(minf, minf, minf, minf, true);
    
    for(auto e : getseg(a, b)){
      //PR(segs[e.F].seg);
      ans = ans + segs[e.F].query(e.S.F, e.S.S + 1);
      //PR(ans.lsum, ans.msum, ans.rsum, ans.all);
      if(a == b) break;
    }
    cout << ans.msum << endl;
  }
END_STACK_EXTEND;
}

Measured memory_bytes: 147340