#include<bits/stdc++.h>
#define sz (1<<18)
using namespace std;

const char ch = ' ';

template < typename T >
int SIZE(const T &a) { return a.size(); }

typedef long long ll;
const ll INF = (1LL<<60);

struct data{
  ll ans,lans,rans,sum;
  data(ll a=INF,ll b=INF,ll c=INF,ll d=INF){
    ans=a,lans=b,rans=c,sum=d;
  }
};

data merge(data a,data b){
  if( a.ans == INF ) return b;
  if( b.ans == INF ) return a;
  ll nans=max(a.rans+b.lans,max(a.ans,b.ans));
  ll nlans=max(a.lans,a.sum+b.lans);
  ll nrans=max(b.rans,b.sum+a.rans);
  ll nsum=a.sum+b.sum;
  return data(nans,nlans,nrans,nsum);
}



struct segtree{
  data tree[sz*2];
  bool f[sz*2];
  ll lazy[sz*2];
  
  void init(){
    for(int i=0;i<sz*2;i++){
      tree[i]=data();
      f[i]=false;
    }
  }
  

  void hyoka(int k,int l,int r,ll x){
    ll nsum=x*(r-l);
    ll nans=max(x,nsum);
    tree[k]=data(nans,nans,nans,nsum);
  }
  
  void reflesh(int k,int l,int r){
    int m=(l+r)/2;
    if(f[k]&&r-l>1){
      f[k]=false;
      f[k*2+1]=f[k*2+2]=true;
      lazy[k*2+1]=lazy[k*2+2]=lazy[k];
      hyoka(k*2+1,l,m,lazy[k]);
      hyoka(k*2+2,m,r,lazy[k]);      
    }
    
    if( r-l>1 ){
      int L=k*2+1,R=k*2+2;
      tree[k]=merge(tree[L],tree[R]);
    }
  }

  void update(int a,int b,int k,int l,int r,int x){
    if(b<=l || r<=a) return;
    int m=(l+r)/2;
    reflesh(k,l,r);
    if(a<=l && r <=b){
      f[k]=1;
      lazy[k]=x;
      hyoka(k,l,r,x);
      return;
    }
    update(a,b,k*2+1,l,m,x);
    update(a,b,k*2+2,m,r,x);
    reflesh(k,l,r);
  }
  
  data dfs(int a,int b,int k,int l,int r){
    if(b<=l || r<=a) return data(INF,INF,INF,INF);
    reflesh(k,l,r);
    
    if(a<=l && r <=b) return tree[k];
    int m=(l+r)/2;
    return merge(dfs(a,b,k*2+1,l,m),dfs(a,b,k*2+2,m,r));
  }
  data get(int l,int r){
    return dfs(l,r,0,0,sz);
  }
};


struct edge{
  int to;
  edge(int a){to=a;}
};

typedef vector<int> vint;
typedef vector<edge> node;
typedef vector<node> graph;

void add_udedge(graph &G, int from,int to){
  G[from].emplace_back(to);
  G[to].emplace_back(from);
}

struct HLD{
  graph G;
  int V;
  int root;
  vint parent,depth,size;
  vint head,index,array;
  void Fdfs(int pos,int prev,int d){
    size[pos]=1;
    parent[pos]=prev;
    depth[pos]=d;
    for(int i=0;i< SIZE(G[pos]) ;i++){
      edge e=G[pos][i];
      if(e.to==prev)continue;
      Fdfs(e.to,pos,d+1);
      size[pos]+=size[e.to];
    }
  }
  
  void Sdfs(int pos){
    int target=-1, maxm=-1;
    for(int i=0;i<SIZE(G[pos]);i++){
      edge e=G[pos][i];
      if(e.to==parent[pos])continue;
      if(maxm<size[e.to]){
	target=e.to;
	maxm=size[e.to];
      }
    }
    index[pos]=SIZE(array);
    array.push_back(pos);
    if(target==-1)return;
    head[target]=head[pos];
    Sdfs(target);
    for(int i=0;i<SIZE(G[pos]);i++){
      edge e=G[pos][i];
      if(e.to==parent[pos]||e.to==target)continue;
      Sdfs(e.to);
    }
    
  }

  void solve(const graph &g,int r){
    G=g;
    V=G.size();
    root=r;
    parent=depth=size=vint(V);
    head=index=vint(V);
    array.clear();
    for(int i=0;i<V;i++)head[i]=i;
    Fdfs(r,root,0);
    Sdfs(r);  
  }

  int lca(int a,int b){
    
    while(head[a]!=head[b]){


      int na=head[a];
      int nb=head[b];
      if(depth[na]>depth[nb])a=parent[na];
      else b=parent[nb];


      //      cout<<a<<ch<<b<<ch<<na<<ch<<nb<<endl;
    }


    return depth[a]<depth[b]?a:b;
  }

  void Path2RangesSecond(int a,int c, vint &L, vint &R, bool inC){
    while( head[a]!=head[c] ){
      int na=parent[head[a]];
      L.push_back(index[head[a]]);
      R.push_back(index[a]+1);
      
      a=na;
    }

    if(inC){
      L.push_back(index[c]);
      R.push_back(index[a]+1);
    }else{
      if(c!=a){
	L.push_back(index[c]+1);
	R.push_back(index[a]+1);
      }
    }
    
  }
  
  void Path2Ranges(int a,int b, vint &L, vint &R){
    int c=lca(a,b);
    Path2RangesSecond(a,c,L,R,true);
    int tmp=L.size();
    Path2RangesSecond(b,c,L,R,false);
    reverse(L.begin()+tmp, L.end());
    reverse(R.begin()+tmp, R.end());
  }
};

segtree T;

int main(){
  int n,q;
  cin>>n>>q;
  vint w(n);
  graph G(n);
  for(int i=0;i<n;i++)cin>>w[i];
  for(int i=0,a,b;i<n-1;i++){
    cin>>a>>b;
    a--,b--;
    add_udedge(G,a,b);
  }
  HLD hld;
  T.init();
  hld.solve(G,n/2);


  
  for(int i=0;i<n;i++){
    int id=hld.index[i];
    T.update(id,id+1,0,0,sz,w[i]);
  }
 
  int t,a,b,c;
  while(q--){
    cin>>t>>a>>b>>c;
    a--,b--;
    if(t==1){
      vint L,R;
      hld.Path2Ranges(a,b,L,R);
      
      for(int i=0;i<SIZE(L);i++){
	T.update(L[i],R[i],0,0,sz,c);
      }
      
    }
    else{
      data tmp;

      c=hld.lca(a,b);

      
      vint L,R;

      hld.Path2RangesSecond(a,c,L,R,true);

      
      for(int i=0;i<SIZE(L);i++){
	
	data ex = T.dfs(L[i],R[i],0,0,sz);
	swap( ex.lans , ex.rans );
	tmp = merge( tmp, ex);
      }
      
      L.clear();
      R.clear();
      hld.Path2RangesSecond(b,c,L,R,false);
      reverse(L.begin(),L.end());
      reverse(R.begin(),R.end());

      
      for(int i=0;i<SIZE(L);i++){
	
	data ex = T.dfs(L[i],R[i],0,0,sz);
	tmp = merge( tmp, ex);
      }
      cout<<tmp.ans<<endl;
    }
    
  }
  return 0;
}



Measured memory_bytes: 70600