#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #if __has_include() #include using namespace atcoder; #endif #define GET_MACRO(_1, _2, _3, NAME, ...) NAME #define _rep(i, n) _rep2(i, 0, n) #define _rep2(i, a, b) for(int i = (int)(a); i < (int)(b); i++) #define rep(...) GET_MACRO(__VA_ARGS__, _rep2, _rep)(__VA_ARGS__) #define all(x) (x).begin(), (x).end() #define rall(x) (x).rbegin(), (x).rend() using i64 = long long; template bool chmin(T& a, const U& b) { return (b < a) ? (a = b, true) : false; } template bool chmax(T& a, const U& b) { return (b > a) ? (a = b, true) : false; } templateistream& operator>>(istream&i,vector&v){rep(j,v.size())i>>v[j];return i;} templatestring join(vector&v){stringstream s;rep(i,v.size())s<<' '<ostream& operator<<(ostream&o,vector&v){if(v.size())o<string join(vector>&vv){string s="\n";rep(i,vv.size())s+=join(vv[i])+"\n";return s;} templateostream& operator<<(ostream&o,vector>&vv){if(vv.size())o< struct SegmentTree { private: std::vector data; int _n, size; void update(int k) { data[k] = op(data[k << 1], data[k << 1 | 1]); } public: SegmentTree(int n) : SegmentTree(std::vector(n, e())) {} SegmentTree(const std::vector& v) : size(int(v.size())) { for (_n = 1; _n < size; _n *= 2); data.resize(2 * _n, e()); for (int i = 0; i < size; i++) data[i + _n] = v[i]; for (int i = _n - 1; i > 0; i--) update(i); } void set(int i, const T x) { assert(0 <= i && i < size); i += _n; data[i] = x; while (i > 1) { i >>= 1; update(i); } } void add(int i, const T x) { assert(0 <= i && i < size); i += _n; data[i] += x; while (i > 1) { i >>= 1; update(i); } } T get(int i) { assert(0 <= i && i < size); return data[i + _n]; } T prod(int l, int r) { assert(0 <= l && l <= r && r <= size); T lf = e(), rf = e(); l += _n; r += _n; while(l < r) { if (l & 1) lf = op(lf, data[l++]); if (r & 1) rf = op(data[--r], rf); l >>= 1; r >>= 1; } return op(lf, rf); } T all_prod() const { return data[1]; } template int min_left(int l, int r, T target) { assert(0 <= l && l <= r && r <= size); int nr = r; l += _n; r += _n; vector lv, rv; while (l < r) { if (l & 1) { lv.push_back(l++); } if (r & 1) { rv.push_back(--r); } l >>= 1; r >>= 1; } while (!rv.empty()) { lv.push_back(rv.back()); rv.pop_back(); } T now = e(); for (auto i: lv) { if (f(op(now, data[i]), target)) { while (true) { if(f(op(now, data[i]), target)) { if (i >= _n) return i - _n; i <<= 1; } else now = op(now, data[i++]); } } else now = op(now, data[i]); } return nr; } template int max_right(int l, int r, T target) { assert(0 <= l && l <= r && r <= size); int nl = l; l += _n; r += _n; vector lv, rv; while (l < r) { if (l & 1) { lv.push_back(l++); } if (r & 1) { rv.push_back(--r); } l >>= 1; r >>= 1; } while (!lv.empty()) { rv.push_back(lv.back()); lv.pop_back(); } T now = e(); for (auto i: rv) { if (f(op(data[i], now), target)) { while (true) { if(f(op(data[i], now), target)) { if (i >= _n) return i - _n; i <<= 1; i++; } else now = op(data[i--], now); } } else now = op(data[i], now); } return nl; } }; vector c; vector> edge; vector dp; vector in, out; int k; void dfs(int now, int p){ in[now] = k; dp[k] = c[now]; k++; for (auto e: edge[now]){ if (e == p) continue; dfs(e, now); } out[now] = k++; return; } int op(int a, int b){ return a ^ b; } int e(){ return 0; } int main(){ cin.tie(nullptr); ios::sync_with_stdio(false); int n, q; cin >> n >> q; c.resize(n); cin >> c; edge.resize(n); dp.resize(2 * n + 10); in.resize(n); out.resize(n); rep(i, n - 1){ int a, b; cin >> a >> b; a--, b--; edge[a].emplace_back(b); edge[b].emplace_back(a); } dfs(0, -1); vector ans; SegmentTree seg(dp); while (q--){ int t, x, y; cin >> t >> x >> y; x--; if (t == 1){ seg.set(in[x], seg.get(in[x]) ^ y); } else{ ans.emplace_back(seg.prod(in[x], out[x])); } } for (auto i: ans) cout << i << "\n"; }