#pragma region header // #pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #include // #include using namespace std; #define all(x) (x).begin(), (x).end() #define isIn(x, y, h, w) ((x) >= 0 && (x) < (h) && (y) >= 0 && (y) < (w)) #define rep(i, n) for(int i = 0; i < (int)(n); i++) #define rrep(i, n) for(auto i = (n) - 1; i >= 0; i--) #define repi(i, n1, n2) for(auto i = (n1); i < (n2); i++) #define rrepi(i, n1, n2) for(auto i = (n2) - 1; i >= (n1); i--) #define rep2(i, j, n) rep(i, n) repi(j, i + 1, n) #define DFS(...) self(self, __VA_ARGS__) #define min_equal(v, x) lower_bound(all(v), (x)) - (v).begin() #define min_over(v, x) upper_bound(all(v), (x)) - (v).begin() #define max_equal(v, x) upper_bound(all(v), (x)) - (v).begin() - 1 #define max_under(v, x) lower_bound(all(v), (x)) - (v).begin() - 1 template static inline vector makevec(const T &n, const U &u){ return vector(n, u); } template static inline auto makevec(const T &n, const Args&... args){ return vector(n, makevec(args...)); } #define in(T, ...) T __VA_ARGS__; input(__VA_ARGS__) #define inrows(n, ...) rep(inrows_, n) inrow(__VA_ARGS__) #define invec(T, n, ...) vector __VA_ARGS__; inputvec(n, __VA_ARGS__); #define invec2(T, n, m, x) vector> x(n, vector(m)); input(x) template istream &operator>>(istream &is, vector &x){ for(auto &&v : x) is >> v; return is; } template inline void input(T&... x){ (cin >> ... >> x); } template inline void inputvec(const T &n){ (void)n; } template inline void inputvec(const T &n, Head &v, Tail&... tail){ v.resize(n); cin >> v; inputvec(n, tail...); } inline void inrow(){} template inline void inrow(Head &x, Tail&... tail){ in(typename Head::value_type, y); x.push_back(y); inrow(tail...); } #define INT(...) in(int, __VA_ARGS__) #define STR(...) in(string, __VA_ARGS__) #define CHAR(...) in(char, __VA_ARGS__) #define VI(n, ...) invec(int, (n), __VA_ARGS__) #define VS(n, ...) invec(string, (n), __VA_ARGS__) #ifdef DEBUG #define dbg(...) cout << #__VA_ARGS__ << ": "; print(__VA_ARGS__); cout << flush #else #define dbg(...) (static_cast(0)) #endif const string DELIMITER[] = #ifdef DEBUG {",", "(", ")", "[", "]"}; #else {" ", "", "", "", ""}; #endif ostream &operator<<(ostream &os, __int128_t x){ if(x < 0) x *= -1, os << '-'; vector v; while(x) v.push_back(x % 10), x /= 10; if(!v.size()) return os << 0; for(int i = (int)v.size() - 1; i >= 0; i--) os << v[i]; return os; } // template ostream &operator<<(ostream &os, const atcoder::static_modint &x){ return os << x.val(); } // template ostream &operator<<(ostream &os, const atcoder::dynamic_modint &x){ return os << x.val(); } template ostream &operator<<(ostream &os, const pair &p){ return os << DELIMITER[1] << p.first << DELIMITER[0] << p.second << DELIMITER[2]; } template && !is_same_v, nullptr_t> = nullptr> ostream &operator<<(ostream &os, const T &c){ for(auto it = c.begin(); it != c.end(); it++) os << DELIMITER[(it == c.begin()) ? 3 : 0] << *it; return os << DELIMITER[4]; } template inline void prend(const T &a){ cout << a << '\n'; exit(0); } template inline void print(const T &a){ cout << a << '\n'; } template inline void print(const Head &a, const Tail&... b){ cout << a << ' '; print(b...); } inline void prec(const int d){ cout << fixed << setprecision(d); } const vector> YN_string = {{"Yes", "No"}, {"YES", "NO"}, {"Takahashi", "Aoki"}, {"Alice", "Bob"}, {"Possible", "Impossible"}}; enum class YesNo{ Yes, YES, taka, alice, poss }; inline void i0(){} template, nullptr_t> = nullptr, class... Tail> inline void i0(T &x, Tail&... tail){ x--; i0(tail...); } template inline void i0(vector &v, Tail&... tail){ for(auto &&x : v) i0(x); i0(tail...); } template inline T div_floor(T a, T b){ if(b < 0) a = -a, b = -b; return a >= 0 ? a / b : (a + 1) / b - 1; } template inline T div_ceil(T a, T b){ if(b < 0) a = -a, b = -b; return a <= 0 ? a / b : (a - 1) / b + 1; } template inline T div_less(T a, T b){ return div_floor(a, b) - !(a % b); } template inline T div_greater(T a, T b){ return div_ceil(a, b) + !(a % b); } template inline void sort(vector &v){ sort(v.begin(), v.end()); } template inline void rsort(vector &v){ sort(v.rbegin(), v.rend()); } template inline void unique(vector &v){ sort(v); v.erase(unique(v.begin(), v.end()), v.end()); } template inline auto min(const T &a){ return *min_element(a.begin(), a.end()); } template inline auto max(const T &a){ return *max_element(a.begin(), a.end()); } template inline bool chmin(T &a, const T &b){ return a > b ? a = b, true : false; } template inline bool chmax(T &a, const T &b){ return a < b ? a = b, true : false; } template inline typename T::value_type mex(const T &st){ for(auto i = typename T::value_type(0); ; i++) if(!st.count(i)) return i; } template inline T calc_sum(const vector &v){ return accumulate(v.begin(), v.end(), T(0)); } using ld = long double; using ll = long long; using l128 = __int128; template using P = pair; template using tup3 = tuple; template using heap = priority_queue, greater>; template using vec2 = vector>; template using vec3 = vector>; template using uset = unordered_set; template using umap = unordered_map; struct FastIO{ FastIO(){ cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); prec(10); } } fastio__; #include #include template using tree = __gnu_pbds::tree, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>; #pragma endregion header #define int long long const int inf = 2e9; const int INF = 2e18; const double EPS = 1e-9; const int MOD = 998244353; using pi = pair; using ipi = pair>; using pii = pair, int>; using vi = vector; using vpi = vector; using vs = vector; using vd = vector; using vvi = vector>; // using mint = atcoder::modint1000000007; // using mint = atcoder::modint998244353; // using mint = atcoder::modint; // using vm = vector; const int dx[] = {0, 1, 0, -1, 1, 1, -1, -1}; const int dy[] = {1, 0, -1, 0, 1, -1, -1, 1}; #define YN YesNo::Yes inline void Yes(bool end = false){ print(YN_string[(int)YN][0]); if(end) exit(0); } inline void No(bool end = false){ print(YN_string[(int)YN][1]); if(end) exit(0); } inline void isYes(bool x, bool end = false){ print(YN_string[(int)YN][!x]); if(end) exit(0); } template struct Edge{ int from, to, id; T cost; Edge(int to, T cost) : to(to), cost(cost){} Edge(int from, int to, T cost) : from(from), to(to), cost(cost){} Edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id){} operator int() const noexcept { return to; } bool operator<(const Edge &e) const{ return cost < e.cost; } }; template using WeightedGraph = vector>>; using Graph = vector>; template using Matrix = vector>; template void add_ud_edge(T &G, const int u, const int v, const Args&... args){ G[u].emplace_back(v, args...); G[v].emplace_back(u, args...); } #define indg(G, n, m) Graph G(n); rep(i, m){ in(int, u, v); G[u - 1].push_back(v - 1); } #define inudg(G, n, m) Graph G(n); rep(i, m){ in(int, u, v); add_ud_edge(G, u - 1, v - 1); } #define inwdg(T, G, n, m) WeightedGraph G(n); rep(i, m){ in(int, u, v); in(T, w); G[u - 1].emplace_back(v - 1, w); } #define inwudg(T, G, n, m) WeightedGraph G(n); rep(i, m){ in(int, u, v); in(T, w); add_ud_edge(G, u - 1, v - 1, w); } namespace bit{ inline bool test(const int s, const int i){ return (s >> i & 1); } inline void set(int &s, const int i){ s |= (1 << i); } inline void reset(int &s, const int i){ s &= ~(1 << i); } inline void flip(int &s, const int i){ s ^= (1 << i); } inline int orb(const int s, const int i){ return s | (1 << i); } inline int notb(const int s, const int i){ return s & ~(1 << i); } inline int xorb(const int s, const int i){ return s ^ (1 << i); } inline int mask(const int n){ return (1 << n) - 1; } inline int next_combination(const int s){ int x = s & -s, y = s + x; return (((s & ~y) / x) >> 1) | y; } #define repset(s, n) rep(s, 1 << (n)) #define repsuperset(s, t, n) for(int s = (t); s < (1 << (n)); ++s |= (t)) #define repsubset(s, t) for(int s = (t), _ = 1; s != (t) || _; --s &= (t), _ = 0) #define repsubsets(s, t, n) repset(t, n) repsubset(s, t) #define repkset(s, n, k) for(int s = (1 << (k)) - 1; s < (1 << (n)); s = next_combination(s)) } template struct modint{ long long a; modint() : a(0){} modint(long long t){ a = t % mod; if(a < 0) a += mod; } operator long long() const{ return a; } bool operator==(const modint &x) const{ return a == x.a; } bool operator!=(const modint &x) const{ return a != x.a; } modint operator-() const{ return modint(a ? (mod - a) : 0); } modint operator~() const{ return pow(mod - 2); } modint inv() const{ return pow(mod - 2); } modint operator+(const modint &x) const{ return modint(*this) += x; } modint operator-(const modint &x) const{ return modint(*this) -= x; } modint operator*(const modint &x) const{ return modint(*this) *= x; } modint operator/(const modint &x) const{ return modint(*this) /= x; } modint &operator+=(const modint &x){ a += x.a; if(a >= mod) a -= mod; return *this; } modint &operator-=(const modint &x){ a -= x.a; if(a < 0) a += mod; return *this; } modint &operator*=(const modint &x){ a = a * x.a % mod; return *this; } modint &operator/=(const modint &x){ a = a * (~x).a % mod; return *this; } friend ostream &operator<<(ostream &os,const modint &x){ return os << x.a; } friend istream &operator>>(istream &is,modint &x){ long long t; is >> t; x = modint(t); return is; } modint pow(long long x) const{ modint ret = 1,tmp = a; for(;x;tmp *= tmp,x >>= 1){ if(x & 1) ret *= tmp; } return ret; } }; using mint = modint<998244353>; signed main(){ INT(n); inudg(G, n, n - 1); VI(n, a); const int MAX = 30; mint ans = 0; rep(t, MAX){ auto dp = makevec(n, 2, mint(0)); auto calc = [&](auto self, int v, int par) -> void{ dp[v][bit::test(a[v], t)] = 1; for(int to : G[v]){ if(to == par) continue; DFS(to, v); mint ndp[2] = {0, 0}; rep(i, 2){ rep(j, 2){ if(!i && !j) continue; rep(k, 2){ ndp[(k + i * j) % 2] += dp[v][k] * dp[to][i]; } } } dp[v][0] = ndp[0]; dp[v][1] = ndp[1]; } }; calc(calc, 0, -1); ans += dp[0][1] * mint(1 << t); } print(ans); }