#include "bits/stdc++.h"
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define ll long long
#define ld double
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ff first
#define ss second
#define ins insert
#define vll vector <ll>
#define vvll vector <vll>
#define vbool vector <bool>
#define pll pair <ll,ll>
#define vpll vector <pll>
#define YY cout<<"YES"
#define NN cout<<"NO"
#define yy cout<<"Yes"
#define nn cout<<"No"
#define set_bits __builtin_popcountll
#define sz(v) (int)v.size()
#define all(v) v.begin(), v.end()
#define allr(v) v.rbegin(), v.rend()
#define desc() greater <ll>()
#define fill1(a,x) for (auto &it: a) it=x;
#define fill2(a,x) for (auto &v: a) { for (auto &it: v) it=x; }
#define endl '\n'   //not to be used in interactive problems
#define random(l,r,T) uniform_int_distribution<T>(l,r)(rng)
#define fastIO ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int M = 1e9+7;
const int MM = 998244353;
const int N = 2e5+7;
const ll inf = 1e18;
const ld eps = 1e-9;
#define PI 3.141592653589793238462

int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
int Dx[]={0,1,1,1,0,-1,-1,-1};
int Dy[]={1,1,0,-1,-1,-1,0,1};


// ********     Policy Based Data Structures     ********
template<class T> using oset = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
template<class key, class value> using omap = tree <key,value,less<key>,rb_tree_tag,tree_order_statistics_node_update>;
// find_by_order(k) -> returns iterator to kth element from start 0
// order_of_key(k) -> returns count of elements < k


// ********     Debug Helper     ********
vector<string> vec_splitter(string s) {
    s += ',';
    vector<string> res;
    while(!s.empty()) {
        res.push_back(s.substr(0, s.find(',')));
        s = s.substr(s.find(',') + 1);
    }
    return res;
}

void debug_out(
vector<string> __attribute__ ((unused)) args,
__attribute__ ((unused)) int idx, 
__attribute__ ((unused)) int LINE_NUM) { cerr << endl; } 
template <typename Head, typename... Tail>
void debug_out(vector<string> args, int idx, int LINE_NUM, Head H, Tail... T) {
    if(idx > 0) cerr << ", "; else cerr << "Line(" << LINE_NUM << ") ";
    stringstream ss; ss << H;
    cerr << args[idx] << " = " << ss.str();
    debug_out(args, idx + 1, LINE_NUM, T...);
}

template<typename C, 
         typename T = std::decay_t<decltype(*begin(std::declval<C>()))>,
         typename std::enable_if<!std::is_same<C, std::string>::value>::type* = nullptr
         >
std::ostream &operator<<(std::ostream &os, const C &container)
{
  bool first = true;
  std::stringstream ss; 
  ss << '[';
  for(const auto &x : container){
    if (!first){
      ss << ", ";
    }
    first = false;
    ss << x;
  }
  ss << ']';
  return os << ss.str();
}

#ifndef ONLINE_JUDGE
    #define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __LINE__, __VA_ARGS__)
#else
    #define debug(...) 42
#endif


// ********     Useful Fuctions     ********
ll gcd(ll a, ll b) { while (b) {a %= b; swap(a,b);} return a; }
ll lcm(ll a, ll b) { ll g=gcd(a,b); ll res=a*(b/g); return res; }
ll extended_gcd(ll a, ll b, ll &x, ll &y) { if (b==0) { x=1; y=0; return a; } ll x1,y1; ll g=extended_gcd(b,a%b,x1,y1); x=y1; y=x1-y1*(a/b); return g; }
ll binExp(ll a, ll b, ll m=M) { a = a % m; ll res = 1; while (b) { if (b&1) { res=(res * a) % m; } a=(a * a) % m; b>>=1; } return res; }
ll mod_inv(ll a, ll m=M) { a = a % m; return binExp(a,m-2,m); }        // only for prime m
ll mod_add(ll a, ll b, ll m=M) { a = a % m; b = b % m; return (((a + b) % m) + m) % m; }
ll mod_sub(ll a, ll b, ll m=M) { a = a % m; b = b % m; return (((a - b) % m) + m) % m; }
ll mod_mul(ll a, ll b, ll m=M) { a = a % m; b = b % m; return (((a * b) % m) + m) % m; }
ll mod_div(ll a, ll b, ll m=M) { a = a % m; ll binv = mod_inv(b,m); return (((a * binv) % m) + m) % m; }
ll sqrtll(ll n) { ll lo=0,hi=3037000499; while (hi-lo>1) { ll m=(hi+lo)/2; if (m*m<=n) { lo=m; } else { hi=m-1; }} if (hi*hi<=n) { return hi; } return lo; }
ld sqrtld(ll n) { ld lo=0,hi=3037000499; while (hi-lo>eps) { ld m=(hi+lo)/2; if ((n-m*m)>eps) { lo=m; } else { hi=m-eps; }} return lo; }
ll cbrtll(ll n) { ll lo=0,hi=2097151; while (hi-lo>1) { ll m=(hi+lo)/2; if (m*m*m<=n) { lo=m; } else { hi=m-1; }} if (hi*hi*hi<=n) { return hi; } return lo; }
ld cbrtld(ll n) { ld lo=0,hi=2097151; while (hi-lo>eps) { ld m=(hi+lo)/2; if ((n-m*m*m)>eps) { lo=m; } else { hi=m-eps; }} return lo; }
void init_usaco() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); }


// ********     Input/Output Template     *********
template<typename T> istream& operator >>(istream &in,vector<T> &v){ for(auto &x:v) in>>x; return in;}
template<typename T> ostream& operator <<(ostream &out,const vector<T> &v){ for(auto &x:v) out<<x<<' '; return out;}
template<typename T1,typename T2> istream& operator >>(istream &in,pair<T1,T2> &p){ in>>p.first>>p.second; return in;}
template<typename T1,typename T2> ostream& operator <<(ostream &out,const pair<T1,T2> &p){ out<<p.first<<' '<<p.second; return out;}


// ********     ACCEPTED     ********
vll color,val;
vll parent,sbtreeSize,lvl,chain,chainHead,positionInHldArr;
vll hldArr,hldValArr;
vll inTime,outTime;
vvll up;
ll pos,chainId;

typedef struct Node
{
    ll w=0,b=0,sumW=0,sumB=0;
}Node;

vector <Node> arr;               // { sum of white, sum of black}
vll lazyarr;            // { 0 -> no update, 1-> update to black node 2-> update to white node}

void dfs(ll node, ll par, ll l, vll adj[])
{
    sbtreeSize[node]=1;
    parent[node]=par;
    up[node][0]=par;
    lvl[node]=l;
    // binary lifting
    for (ll i=1;i<20;i++)
    {
        if (up[node][i-1]!=-1)
            up[node][i]=up[up[node][i-1]][i-1];
        else
            up[node][i]=-1;
    }
    for (auto &it: adj[node])
    {
        if (it!=par)
        {
            dfs(it,node,l+1,adj);
            sbtreeSize[node]+=sbtreeSize[it];
        }
    }
}

ll lift_node(ll node, ll k)
{
    for (ll i=19;i>=0 && node!=-1;i--)
    {
        if (k&(1LL<<i))
            node=up[node][i];
    }
    return node;
}
 
ll LCA(ll a, ll b)
{
    if (lvl[a]<lvl[b]) swap(a,b);
    a=lift_node(a,lvl[a]-lvl[b]);
    if (a==b) return a;
    for (ll i=19;i>=0;i--)
    {
        ll para=up[a][i];
        ll parb=up[b][i];
        if (para!=parb)
        {
            a=para;
            b=parb;
        }
    }
    return lift_node(a,1);
}

void HLD(ll node, ll par, vll adj[])
{
    chain[node]=chainId;
    hldArr[pos]=node;
    hldValArr[pos]=val[node];
    positionInHldArr[node]=pos;
    inTime[node]=pos++;
    ll heavyChild=-1,heavySize=0;
    for (auto &it: adj[node])
    {
        if (it!=par)
        {
            if (sbtreeSize[it]>heavySize)
            {
                heavySize=sbtreeSize[it];
                heavyChild=it;
            }
        }
    }
    if (heavySize>0) HLD(heavyChild,node,adj);  // not leaf, move to heavy edge
    for (auto &it: adj[node])
    {
        if (it!=par && it!=heavyChild)
        {
            chainHead[++chainId]=it;
            HLD(it,node,adj);
        }
    }
    outTime[node]=pos-1;
}

void merge(ll ind, ll left, ll right)
{
    arr[ind].w=arr[left].w+arr[right].w;
    arr[ind].b=arr[left].b+arr[right].b;
    arr[ind].sumW=arr[left].sumW+arr[right].sumW;
    arr[ind].sumB=arr[left].sumB+arr[right].sumB;
}

void update_lazy(ll ind, ll lo, ll hi)
{
    if (lazyarr[ind]==0) return;
    ll upd=lazyarr[ind];
    lazyarr[ind]=0;
    if (upd==1)
    {
        arr[ind].w+=arr[ind].b;
        arr[ind].sumW+=arr[ind].sumB;
        arr[ind].b=arr[ind].sumB=0;
    }
    else
    {
        arr[ind].b+=arr[ind].w;
        arr[ind].sumB+=arr[ind].sumW;
        arr[ind].w=arr[ind].sumW=0;
    }
    if (lo!=hi) lazyarr[2*ind+1]=upd, lazyarr[2*ind+2]=upd;
}

void buildSegTree(ll ind, ll lo, ll hi)
{
    if (lo==hi)
    {
        arr[ind].w=1;
        arr[ind].sumW=hldValArr[lo];
        arr[ind].b=arr[ind].sumB=0;
        return;
    }
    ll mid=(hi+lo)/2;
    buildSegTree(2*ind+1,lo,mid);
    buildSegTree(2*ind+2,mid+1,hi);
    merge(ind,2*ind+1,2*ind+2);
}

/*Query:
1 -> get white count
2 -> get black count
3 -> get sum white
4 -> get sum black*/

ll querySegTree(ll ind, ll lo, ll hi, ll l, ll r, ll d)
{
    // check for update
    update_lazy(ind,lo,hi);
    if (lo>r || hi<l) return 0;
    else if (lo>=l && hi<=r)
    {
        if (d==1) return arr[ind].w;
        else if (d==2) return arr[ind].b;
        else if (d==3) return arr[ind].sumW;
        else return arr[ind].sumB;
    }
    ll mid=(hi+lo)/2;
    ll left=querySegTree(2*ind+1,lo,mid,l,r,d);
    ll right=querySegTree(2*ind+2,mid+1,hi,l,r,d);
    ll ans=left+right;
    return ans;
}

/*Update:
1 -> force all white
2 -> force all black*/

void updateSegTree(ll ind, ll lo, ll hi, ll l, ll r, ll x)
{
    // check for update
    update_lazy(ind,lo,hi);
    if (lo>r || hi<l) return;
    else if (lo>=l && hi<=r)
    {
        if (x==1)
        {
            arr[ind].w+=arr[ind].b;
            arr[ind].sumW+=arr[ind].sumB;
            arr[ind].b=arr[ind].sumB=0;
        }
        else
        {
            arr[ind].b+=arr[ind].w;
            arr[ind].sumB+=arr[ind].sumW;
            arr[ind].w=arr[ind].sumW=0;
        }
        if (lo!=hi) lazyarr[2*ind+1]=x, lazyarr[2*ind+2]=x;
        return;
    }
    ll mid=(hi+lo)/2;
    updateSegTree(2*ind+1,lo,mid,l,r,x);
    updateSegTree(2*ind+2,mid+1,hi,l,r,x);
    merge(ind,2*ind+1,2*ind+2);
}

void hld_query1()
{
    ll n=sz(hldArr);
    ll x,y; cin>>x>>y; x--; y--;
    ll lca=LCA(x,y);
    ll whiteCnt=0,blackCnt=0;
    ll a=x,b=y;
    while (chain[a]!=chain[lca])
    {
        whiteCnt+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[a]]],positionInHldArr[a],1);
        blackCnt+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[a]]],positionInHldArr[a],2);
        a=up[chainHead[chain[a]]][0];
    }
    whiteCnt+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[a],1);
    blackCnt+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[a],2);
    while (chain[b]!=chain[lca])
    {
        whiteCnt+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[b]]],positionInHldArr[b],1);
        blackCnt+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[b]]],positionInHldArr[b],2);
        b=up[chainHead[chain[b]]][0];
    }
    whiteCnt+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[b],1);
    blackCnt+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[b],2);
    if (querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[lca],1)==1) whiteCnt--;
    else blackCnt--;
    if (whiteCnt>blackCnt)
    {
        // force white in path
        a=x,b=y;
        while (chain[a]!=chain[lca])
        {
            updateSegTree(0,0,n-1,positionInHldArr[chainHead[chain[a]]],positionInHldArr[a],1);
            a=up[chainHead[chain[a]]][0];
        }
        updateSegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[a],1);
        while (chain[b]!=chain[lca])
        {
            updateSegTree(0,0,n-1,positionInHldArr[chainHead[chain[b]]],positionInHldArr[b],1);
            b=up[chainHead[chain[b]]][0];
        }
        updateSegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[b],1);
    }
    else if (blackCnt>whiteCnt)
    {
        // force black in path
        a=x,b=y;
        while (chain[a]!=chain[lca])
        {
            updateSegTree(0,0,n-1,positionInHldArr[chainHead[chain[a]]],positionInHldArr[a],2);
            a=up[chainHead[chain[a]]][0];
        }
        updateSegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[a],2);
        while (chain[b]!=chain[lca])
        {
            updateSegTree(0,0,n-1,positionInHldArr[chainHead[chain[b]]],positionInHldArr[b],2);
            b=up[chainHead[chain[b]]][0];
        }
        updateSegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[b],2);
    }
}

void hld_query2()
{
    ll n=sz(hldArr);
    ll x; cin>>x; x--;
    // color subtree x with black
    updateSegTree(0,0,n-1,inTime[x],outTime[x],2);
}

ll hld_query3()
{
    ll n=sz(hldArr);
    ll x,y; cin>>x>>y; x--; y--;
    ll lca=LCA(x,y);
    ll whiteSum=0,blackSum=0;
    ll a=x,b=y;
    while (chain[a]!=chain[lca])
    {
        whiteSum+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[a]]],positionInHldArr[a],3);
        blackSum+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[a]]],positionInHldArr[a],4);
        a=up[chainHead[chain[a]]][0];
    }
    whiteSum+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[a],3);
    blackSum+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[a],4);
    while (chain[b]!=chain[lca])
    {
        whiteSum+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[b]]],positionInHldArr[b],3);
        blackSum+=querySegTree(0,0,n-1,positionInHldArr[chainHead[chain[b]]],positionInHldArr[b],4);
        b=up[chainHead[chain[b]]][0];
    }
    whiteSum+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[b],3);
    blackSum+=querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[b],4);
    if (querySegTree(0,0,n-1,positionInHldArr[lca],positionInHldArr[lca],1)==1) whiteSum-=val[lca];
    else blackSum-=val[lca];
    return max(whiteSum,blackSum);
}

void solve()
{
    ll n,m; cin>>n>>m;
    hldArr.resize(n);
    hldValArr.resize(n);
    vll adj[n];
    for (ll i=0;i<n-1;i++)
    {
        ll u,v; cin>>u>>v; u--; v--;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    val.resize(n); cin>>val;
    color.resize(n,0);
    parent.resize(n);
    sbtreeSize.resize(n);
    lvl.resize(n);
    chain.resize(n);
    chainHead.resize(n);
    positionInHldArr.resize(n);
    inTime.resize(n);
    outTime.resize(n);
    up.resize(n, vll (20,-1));
    arr.resize(4*n);
    lazyarr.resize(4*n,0);
    dfs(0,-1,0,adj);
    pos=chainId=0;
    HLD(0,-1,adj);
    debug(hldArr);
    debug(hldValArr);
    debug(inTime);
    debug(outTime);
    buildSegTree(0,0,n-1);
    while (m--)
    {
        ll q; cin>>q;
        if (q==1) hld_query1();
        else if (q==2) hld_query2();
        else cout<<hld_query3()<<endl;
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
        // freopen("input.txt","r",stdin);
        // freopen("output.txt","w",stdout);
        freopen("error.txt","w",stderr);
        clock_t clk = clock();
    #endif
    // init_usaco();
    fastIO;
    int t=1;
    // cin>>t;
    for (int test=1;test<=t;test++)
    {
        // cout<<"Case #"<<test<<": ";
        solve();
        cout<<endl;
    }
    #ifndef ONLINE_JUDGE
          cerr << '\n'<<"Time (in s): " << double(clock() - clk) * 1.0 / CLOCKS_PER_SEC << '\n';
    #endif
    return 0;
}
