Link to this code: https://cses.fi/paste/630824ed20ff4ffbddc766/
/* 777 */

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

const int MAX_N = 2e6 + 5;
// LCA
int dep[MAX_N], first[MAX_N];
vector<int> euler;

// ---------------- Sparse Table -------------
int highestPowerOf2(uint32_t x) {
    return 31 - __builtin_clz(x);
}
class SparseTable {
    int N, L;
    vector<vector<int>> table;

   public:
    SparseTable(int n) {
        this->N = n;
        this->L = highestPowerOf2(n) + 1;
        this->table.resize(n, vector<int>(this->L, -1));
        // table[i][k] -> stores the index in the euler tour which has minimum
        // depth of `2^k` elements from `i`
    }

    void build() {
        for (int i = 0; i < N; ++i) {
            table[i][0] = i;
        }
        for (int k = 1; k < L; ++k) {
            for (int i = 0; i < N - (1 << k) + 1; ++i) {
                int x = table[i][k - 1], y = table[i + (1 << (k - 1))][k - 1];
                int dx = dep[euler[x]], dy = dep[euler[y]];
                table[i][k] = dx < dy ? x : y;
            }
        }
    }

    int query(int l, int r) {
        int k = highestPowerOf2(r - l + 1);
        int x = table[l][k], y = table[r - (1 << k) + 1][k];
        int dx = dep[euler[x]], dy = dep[euler[y]];
        return dx < dy ? x : y;
    }
};

// ----------------- BIT/Fenwick Tree on ETT ----------------------
class FenwickTree {
   private:
    int N;
    vector<int> B1, B2;  // 1-based

    int _query(vector<int>& B, int i) {
        int s = 0;
        for (; i; i -= i & -i) s += B[i];
        return s;
    }

    void _update(vector<int>& B, int i, int d) {
        for (; i < N; i += i & -i) B[i] += d;
    }

   public:
    FenwickTree(int n) {
        N = n + 1;
        B1.resize(N, 0);
        B2.resize(N, 0);
    }

    void update(int l, int r, int d) {
        _update(B1, l, d);
        _update(B1, r + 1, -d);
        _update(B2, l, -d * (l - 1));
        _update(B2, r + 1, d * r);
    }

    int prefSum(int i) { return _query(B1, i) * i + _query(B2, i); }

    int query(int l, int r) { return prefSum(r) - prefSum(l - 1); }
};

// ---------------- declare ----------------------

int N, root = 1, timer;
int in[MAX_N], out[MAX_N], vals[MAX_N], flat[2 * MAX_N];
vector<int> tree[MAX_N];  // 1-based
SparseTable* SPT;         // 0-based
FenwickTree* FT;          // 1-based

// ---------------- build ----------------------

void add_edge(int u, int v) {
    tree[u].push_back(v);
    tree[v].push_back(u);
}

void reset_tree(int n) {
    timer = 0;
    for (int i = 0; i <= n; ++i) {
        tree[i].clear();
        in[i] = out[i] = vals[i] = flat[i] = flat[n + i] = dep[i] = 0;
        first[i] = -1;
    }
    euler.clear();
    delete SPT;
    delete FT;
}

// ----------------- 2N ETT ---------------------

// assign in (entry) and out (exit) times
void euler_dfs(int u = 1, int p = -1) {
    in[u] = ++timer;  // increase timer at entry
    if (p != -1) dep[u] = dep[p] + 1;
    if (first[u] == -1) first[u] = (int) euler.size();
    euler.push_back(u);
    for (int v : tree[u]) {
        if (v == p) continue;
        euler_dfs(v, u);
        euler.push_back(u);
    }
    out[u] = ++timer;  // increase timer at exit (unique times)
}

// subtree/ancestor check in O(1), anc=ancestor, des=descendant
bool is_ancestor(int anc, int des) {
    return in[anc] < in[des] && out[des] < out[anc];
}

// subtree size in O(1)
int get_sub_sz(int u) {
    return (out[u] - in[u] + 1) >> 1;
}

// flatten into array (base array) in O(N)
void flatten() {
    for (int u = 1; u <= N; ++u) {
        flat[in[u]] = vals[u];

        // cancelling out
        flat[out[u]] = -vals[u];  // sum
        // flat[out[u]] = vals[u];  // XOR
        // flat[out[u]] = 0;  // gcd
    }
}

// ----------------- operations ----------------------

// update the value of node `u` to x=new value
void node_update(int u, int x) {
    int i = in[u], j = out[u];
    FT->update(i, i, (x - flat[i]));  // 1-based
    FT->update(j, j, -x - flat[j]);   // 1-based
    flat[i] = x;
    flat[j] = -x;  // sum
    // flat[j] = x; // xor
}

// perform query over path from root to b
int root_query(int u) {
    int l = in[root], r = in[u], res;
    res = FT->query(l, r);
    return res;
}

int lca(int a, int b) {
    int l = first[a], r = first[b];
    if (l > r) swap(l, r);
    int idx = SPT->query(l, r);  //  index of min(depth[l..r]) in euler[l..r]
    return euler[idx];
}

// perform query over path from a to b
int path_query(int a, int b) {
    int l = lca(a, b);
    return root_query(a) + root_query(b) - 2 * root_query(l) + flat[in[l]];
}

// ----------------- debug ----------------------

void print_DS() {
    for (int i = 1; i <= N; ++i) cout << i << " ";
    cout << endl;
    for (int i = 1; i <= N; ++i) cout << in[i] << " ";
    cout << endl;
    for (int i = 1; i <= N; ++i) cout << out[i] << " ";
    cout << endl;
    for (int i = 1; i <= N; ++i) cout << dep[i] << " ";
    cout << endl;
    for (int x : euler) cout << x << " ";
    cout << endl;
    for (int i = 1; i <= 2 * N; ++i) cout << flat[i] << " ";
    cout << endl;
}

// ----------------- code ----------------------

void solve() {
    int Q;
    cin >> N >> Q;

    reset_tree(N);  // in case of multiple test cases

    for (int i = 1; i <= N; ++i) cin >> vals[i];
    for (int i = 0; i < N - 1; ++i) {
        int u, v;
        cin >> u >> v;
        // u++;v++ // for 0-based nodes
        add_edge(u, v);
    }

    // ETT (Euler Tour in Trees) or Tree Flattening or In-Out - Subtree Queries
    euler_dfs(1, -1);
    flatten();

    // ---LCA---
    SPT = new SparseTable((int) euler.size());
    SPT->build();

    // ---Path Queries (invertible=sum/XOR/...)---
    FT = new FenwickTree(2 * N);
    for (int i = 1; i <= 2 * N; ++i) FT->update(i, i, flat[i]);

    vector<int> qs;
    for (int q = 0; q < Q; ++q) {
        int ty, u, v = root, n_val;  // u=node, v=node, n_val=new value
        cin >> ty >> u;
        if (ty == 1) {  // update
            cin >> n_val;
            node_update(u, n_val);
        } else if (ty == 2) {  // query
            // cin >> v;
            int res = path_query(u, v);
            qs.push_back(res);
        }
    }

    for (int x : qs) cout << x << '\n';

    // ---DEBUG---
    // print_DS();
}

int32_t main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    // cin >> T; // multiple test cases
    while (T--) solve();
    return 0;
}

// archive
/*
// baseline version of tree flattening into an array
// tweak / make changes to out[u]th index based on what the problem is asking
void flatten() {
    for (int u = 1; u <= N; ++u) {
        flat[in[u]] = vals[u];
        flat[out[u]] = vals[u];
    }
}
*/