#include<bits/stdc++.h>
using namespace std;

#define IOS  ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define ll               long long
#define pb               push_back
#define vll              vector<ll>
#define pll              pair<ll,ll>
#define vpll             vector<pll>
#define all(v) v.begin(),v.end()


const int N = 1e5+7;
ll time_in = 0; ll idx = 0; ll n,m,q; 
vll value(N),color(N),left_range_(N),right_range_(N),parent(N,0),depth(N,0),subtree_size(N,0),heavy(N,0);   
vll head(N,0),lt(N,0),pos(N,0),pos_out(N,0);

void dfs(int node,int par,vll adj[],int dep){
    parent[node] = par;
    depth[node] = dep;
    for(auto x: adj[node]){
        if(x != par){
            dfs(x,node,adj,dep+1);
            subtree_size[node] += subtree_size[x]; 
            if(subtree_size[x] >  subtree_size[heavy[node]]){
                heavy[node] = x;
            }
        }
    }
    subtree_size[node]++;
} 

ll lca(ll x,ll y){   
        while(head[x] != head[y]){
            if(depth[head[x]] < depth[head[y]]) swap(x,y);
            x = parent[head[x]];
        }
        if(depth[x] < depth[y]) swap(x,y);
    return y;
}
void dfsHLD(int node,vll adj[], ll chain){
    head[node] = chain;
    lt[idx] = value[node];
    pos[node] = idx++;
    if(heavy[node] != 0){
        dfsHLD(heavy[node],adj,chain);
    }
    for(auto x: adj[node]){
        if(x != parent[node] and x != heavy[node]){
                dfsHLD(x,adj,x);
        }
    } 
    pos_out[node] = idx;
}



vpll arr;
vll lazyarr;

void merge(ll ind, ll left, ll right)
{
    arr[ind]=arr[left];
    arr[ind].first+=arr[right].first;
    arr[ind].second+=arr[right].second;
}

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].first+=arr[ind].second, arr[ind].second=0;
    else
        arr[ind].second+=arr[ind].first, arr[ind].first=0;
    if (lo!=hi)
        lazyarr[2*ind+1]=upd, lazyarr[2*ind+2]=upd;
}

void build(ll ind, ll lo, ll hi, vll &v)
{
    if (lo==hi)
    {
        if (v[lo]>=0) arr[ind].first=v[lo], arr[ind].second=0;
        else arr[ind].first=0, arr[ind].second=-v[lo];
        return;
    }
    ll mid=(hi+lo)/2;
    build(2*ind+1,lo,mid,v);
    build(2*ind+2,mid+1,hi,v);
    merge(ind,2*ind+1,2*ind+2);
}

void update(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;
    else if (lo>=l && hi<=r)
    {
        if (d==1)
            arr[ind].first+=arr[ind].second, arr[ind].second=0;
        else
            arr[ind].second+=arr[ind].first, arr[ind].first=0;
        if (lo!=hi)
            lazyarr[2*ind+1]=d, lazyarr[2*ind+2]=d;
    }
    else
    {
        ll mid=(hi+lo)/2;
        update(2*ind+1,lo,mid,l,r,d);
        update(2*ind+2,mid+1,hi,l,r,d);
        merge(ind,2*ind+1,2*ind+2);
    }
}

ll query(ll ind, ll lo, ll hi, ll l, ll r)
{
    // check for update
    update_lazy(ind,lo,hi);
    if (lo>r || hi<l) return 0;
    else if (lo>=l && hi<=r) return arr[ind].first-arr[ind].second;
    ll mid=(hi+lo)/2;
    ll left=query(2*ind+1,lo,mid,l,r);
    ll right=query(2*ind+2,mid+1,hi,l,r);
    ll ans=left+right;
    return ans;
}

vpll brr;  // { count 0, count 1}
vll lazy;
// 0 -> no update_color
// 1 -> force 0
// 2 -> force 1

void merge_color(ll ind, ll left, ll right)
{
    brr[ind]=brr[left];
    brr[ind].first+=brr[right].first;
    brr[ind].second+=brr[right].second;
}

void update_lazy_color(ll ind, ll lo, ll hi)
{
    if (lazy[ind]==0) return;
    ll elem=hi-lo+1;
    ll upd=lazy[ind];
    if (lazy[ind]==1) brr[ind]={elem,0};
    else brr[ind]={0,elem};
    lazy[ind]=0;
    if (lo!=hi) lazy[2*ind+1]=upd, lazy[2*ind+2]=upd;
}

void build_color(ll ind, ll lo, ll hi, vll &v)
{
    if (lo==hi)
    {
        if (v[lo]==0) brr[ind]={1,0};
        else brr[ind]={0,1};
        return;
    }
    ll mid=(hi+lo)/2;
    build_color(2*ind+1,lo,mid,v);
    build_color(2*ind+2,mid+1,hi,v);
    merge_color(ind,2*ind+1,2*ind+2);
}

void update_color(ll ind, ll lo, ll hi, ll l, ll r, ll x)
{
    // check update_color in lazy
    update_lazy_color(ind,lo,hi);
    if (lo>r || hi<l) return;
    else if (lo>=l && hi<=r)
    {
        ll elem=hi-lo+1;
        if (x==1) brr[ind]={elem,0};
        else brr[ind]={0,elem};
        if (lo!=hi) lazy[2*ind+1]=x, lazy[2*ind+2]=x;
    }
    else
    {
        ll mid=(hi+lo)/2;
        update_color(2*ind+1,lo,mid,l,r,x);
        update_color(2*ind+2,mid+1,hi,l,r,x);
        merge_color(ind,2*ind+1,2*ind+2);
    }
}

ll query_color(ll ind, ll lo, ll hi, ll l, ll r)
{
    // check update_color in lazy
    update_lazy_color(ind,lo,hi);
    if (lo>r || hi<l) return 0;
    else if (lo>=l && hi<=r) return brr[ind].second;
    ll mid=(hi+lo)/2;
    ll left=query_color(2*ind+1,lo,mid,l,r);
    ll right=query_color(2*ind+2,mid+1,hi,l,r);
    ll ans=left+right;
    return ans;
}


ll get_the_value_color(int x,int y){
    ll sum = 0;
    while(head[x] != head[y]){
        if(depth[head[x]] < depth[head[y]]) swap(x,y);
        ll value = query_color(0,0,n-1,pos[head[x]], pos[x]);
        sum += value;
        x = parent[head[x]];
    }    
    if(depth[x] < depth[y]) swap(x,y);
    ll value = query_color(0,0,n-1,pos[y],pos[x]);
    if(pos[x] >= pos[y]) sum += value;
    return sum;
}


void update_the_color(int x,int y,int color){
    while(head[x] != head[y]){
        if(depth[head[x]] < depth[head[y]]) swap(x,y);
        update_color(0,0,n-1,pos[head[x]],pos[x],color);
        x = parent[head[x]];
    }    
    if(depth[x] < depth[y]) swap(x,y);
    if(pos[x] >= pos[y] )update_color(0,0,n-1,pos[y],pos[x],color);
}

void update_the_value(int x,int y,int sign){
    while(head[x] != head[y]){
        if(depth[head[x]] < depth[head[y]]) swap(x,y);
        update(0,0,n-1,pos[head[x]],pos[x],sign);
        x = parent[head[x]];
    }    
    if(depth[x] < depth[y]) swap(x,y);
    if(pos[x] >= pos[y] )update(0,0,n-1,pos[y],pos[x],sign);
}


ll get_the_value(int x,int y){
     ll sum = 0;
    while(head[x] != head[y]){
        if(depth[head[x]] < depth[head[y]]) swap(x,y);
        ll value =  query(0,0,n-1,pos[head[x]],pos[x]);
        sum += value;
        x = parent[head[x]];
    }    
    if(depth[x] < depth[y]) swap(x,y);
    ll value = query(0,0,n-1,pos[y],pos[x]);
    if(pos[x] >= pos[y]) sum += value;
    return sum;
}

template<typename Node, typename Update>
struct SegTree {
    vector<Node> tree;
    vector<ll> arr; // type may change
    int n;
    int s;
    SegTree(int a_len, vector<ll> &a) { // change if type updated
        arr = a;
        n = a_len;
        s = 1;
        while(s < 2 * n){
            s = s << 1;
        }
        tree.resize(s); fill(all(tree), Node());
        build(0, n - 1, 1);
    }
    void build(int start, int end, int index)  // Never change this
    {
        if (start == end)   {
            tree[index] = Node(arr[start]);
            return;
        }
        int mid = (start + end) / 2;
        build(start, mid, 2 * index);
        build(mid + 1, end, 2 * index + 1);
        tree[index].merge(tree[2 * index], tree[2 * index + 1]);
    }
    void update(int start, int end, int index, int query_index, Update &u)  // Never Change this
    {
        if (start == end) {
            u.apply(tree[index]);
            return;
        }
        int mid = (start + end) / 2;
        if (mid >= query_index)
            update(start, mid, 2 * index, query_index, u);
        else
            update(mid + 1, end, 2 * index + 1, query_index, u);
        tree[index].merge(tree[2 * index], tree[2 * index + 1]);
    }
    Node query(int start, int end, int index, int left, int right) { // Never change this
        if (start > right || end < left)
            return Node();
        if (start >= left && end <= right)
            return tree[index];
        int mid = (start + end) / 2;
        Node l, r, ans;
        l = query(start, mid, 2 * index, left, right);
        r = query(mid + 1, end, 2 * index + 1, left, right);
        ans.merge(l, r);
        return ans;
    }
    void make_update(int index, ll val) {  // pass in as many parameters as required
        Update new_update = Update(val); // may change
        update(0, n - 1, 1, index, new_update);
    }
    Node make_query(int left, int right) {
        return query(0, n - 1, 1, left, right);
    }
};

// all positive


struct Node1 {
    ll val; // may change
    Node1() { // Identity element
        val = 0;    // may change
    }
    Node1(ll p1) {  // Actual Node
        val = p1; // may change
    }
    void merge(Node1 &l, Node1 &r) { // Merge two child nodes
        val = l.val + r.val;  // may change
    }
};

struct Update1 {
    ll val; // may change
    Update1(ll p1) { // Actual Update
        val = p1; // may change
    }
    void apply(Node1 &a) { // apply update to given node
        a.val = val; // may change
    }
};


void solve() {
   cin>>n>>q;
    assert(n >= 1 and n <= 100000);
    assert(q >= 1 and q <= 100000);
    color.resize(n + 1); value.resize(n + 1); 
    for(int i = 0; i< n; i++) color[i] = 0;
    arr.clear(); lazyarr.clear(); arr.resize(4*n+1); lazyarr.resize(4*n+1,0);
    brr.clear(); lazy.clear(); brr.resize(4*n+1); lazy.resize(4*n+1,0);
    vector<ll> adj[n + 1];
    for(int i = 0; i< n-1; i++){
        ll x,y; cin>>x>>y;
        assert(x >= 1 and x <= n); assert(y >= 1 and y <= n);
        adj[x].push_back(y);
        adj[y].pb(x);
    }
    for(int i = 1; i<= n; i++) cin>>value[i];
    parent.resize(n + 1);  depth.resize(n + 1); subtree_size.resize(n + 1); heavy.resize(n + 1); head.resize(n + 1);
    lt.resize(n + 1); pos.resize(n + 1); pos_out.resize(n + 1); 
    dfs(1,0,adj,0); // main dfs calling
    dfsHLD(1,adj,1); // hld dfs calling
    auto lt1 = lt; // decomposed array after HLD
    build(0,0,n-1,lt); // segment tree for the mix of black and white node values
    build_color(0,0,n-1,color); // segment tree for saving the color white and black nodes
    SegTree<Node1,Update1> sg = SegTree<Node1,Update1> (n,lt1); // segment tree storing all the original values
    //all nodes are considered positive means all nodes are black first
    update(0,0,n-1,0,n-1,-1); // coloring all the node white first
    for(int i = 0; i < q; i++){
        int qType; cin>>qType;
        assert(qType >= 1 and qType <= 3);
        if(qType == 1){
            ll x,y ;cin>>x>>y;
            assert(x >= 1 and x <= n);
            assert(y >= 1 and y <= n);
            ll lca_node = lca(x,y);
            ll path_dist = abs(depth[lca_node] - depth[x]) + abs(depth[lca_node] - depth[y]) + 1;
            ll black_nodes = get_the_value_color(x,y);
            ll white_nodes = path_dist - black_nodes;
            if(black_nodes > white_nodes){
                update_the_color(x,y,2);
                update_the_value(x,y,1);
            }else if(black_nodes < white_nodes){
                update_the_color(x,y,1);
                update_the_value(x,y,-1);
            }
        }else if(qType == 2){
                ll x; cin>>x;
                assert(x >= 1 and x <= n);
                update_color(0,0,n-1,pos[x], pos_out[x] - 1,2); // changing the color of the subtree
                update(0,0,n-1,pos[x], pos_out[x] - 1,1); // change the subtree with positive values means black nodes
        }else{
                ll a,b ;cin>>a>>b;
                assert(a >= 1 and a <= n);
                assert(b >= 1 and b <= n);
                ll x,y; x = a; y = b;
                ll total_value = 0;
                while(head[x] != head[y]){
                    if(depth[head[x]] < depth[head[y]]) swap(x,y);
                    total_value += sg.make_query(pos[head[x]],pos[x]).val;
                    x = parent[head[x]];
                }    
                if(depth[x] < depth[y]) swap(x,y);
                if(pos[x] >= pos[y]) total_value += sg.make_query(pos[y],pos[x]).val;
                // total_value --> getting the original values considered all nodes are black
                ll path_value = get_the_value(a,b); // getting the values where both positive and negative values are there
                ll black_value = (total_value + path_value) / 2;
                ll white_value = (total_value - path_value) / 2;
                cout<<max(white_value,black_value)<<endl;
        }        
    }
}
 
int main()
 {
     IOS;
 
 #ifndef ONLINE_JUDGE
     freopen("error.txt", "w", stderr);
 #endif
     int test = 1;
     // cin >> test;
     for (int i = 1; i <= test; i++) {
         // cout << "Case " << i << ": "<<endl;
        solve();
     }
     return 0;
 }
