#pragma GCC optimize("Ofast") #pragma GCC optimize("unroll-loops") #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using Int = long long; template ostream &operator<<(ostream &os, const pair &a) { return os << "(" << a.first << ", " << a.second << ")"; }; template ostream &operator<<(ostream &os, const vector &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; } template void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; } template bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; } template bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; } // fast IO by yosupo // sc.read(string &) appends the input struct Scanner { FILE* fp = nullptr; char line[(1 << 15) + 1]; size_t st = 0, ed = 0; void reread() { memmove(line, line + st, ed - st); ed -= st; st = 0; ed += fread(line + ed, 1, (1 << 15) - ed, fp); line[ed] = '\0'; } bool succ() { while (true) { if (st == ed) { reread(); if (st == ed) return false; } while (st != ed && isspace(line[st])) st++; if (st != ed) break; } if (ed - st <= 50) reread(); return true; } template ::value, int> = 0> bool read_single(T& ref) { if (!succ()) return false; while (true) { size_t sz = 0; while (st + sz < ed && !isspace(line[st + sz])) sz++; ref.append(line + st, sz); st += sz; if (!sz || st != ed) break; reread(); } return true; } template ::value, int> = 0> bool read_single(T& ref) { if (!succ()) return false; bool neg = false; if (line[st] == '-') { neg = true; st++; } ref = T(0); while (isdigit(line[st])) { ref = 10 * ref + (line[st++] - '0'); } if (neg) ref = -ref; return true; } template bool read_single(vector& ref) { for (auto& d : ref) { if (!read_single(d)) return false; } return true; } void read() {} template void read(H& h, T&... t) { bool f = read_single(h); assert(f); read(t...); } Scanner(FILE* _fp) : fp(_fp) {} }; struct Printer { public: template void write() {} template void write(const H& h, const T&... t) { if (F) write_single(' '); write_single(h); write(t...); } template void writeln(const T&... t) { write(t...); write_single('\n'); } Printer(FILE* _fp) : fp(_fp) {} ~Printer() { flush(); } private: static constexpr size_t SIZE = 1 << 15; FILE* fp; char line[SIZE], small[50]; size_t pos = 0; void flush() { fwrite(line, 1, pos, fp); pos = 0; } void write_single(const char& val) { if (pos == SIZE) flush(); line[pos++] = val; } template ::value, int> = 0> void write_single(T val) { if (pos > (1 << 15) - 50) flush(); if (val == 0) { write_single('0'); return; } if (val < 0) { write_single('-'); val = -val; // todo min } size_t len = 0; while (val) { small[len++] = char('0' + (val % 10)); val /= 10; } for (size_t i = 0; i < len; i++) { line[pos + i] = small[len - 1 - i]; } pos += len; } void write_single(const string& s) { for (char c : s) write_single(c); } void write_single(const char* s) { size_t len = strlen(s); for (size_t i = 0; i < len; i++) write_single(s[i]); } template void write_single(const vector& val) { auto n = val.size(); for (size_t i = 0; i < n; i++) { if (i) write_single(' '); write_single(val[i]); } } void write_single(long double d){ { long long v=d; write_single(v); d-=v; } write_single('.'); for(int _=0;_<8;_++){ d*=10; long long v=d; write_single(v); d-=v; } } }; Scanner sc(stdin); Printer pr(stdout); //////////////////////////////////////////////////////////////////////////////// template struct ModInt { static constexpr unsigned M = M_; unsigned x; constexpr ModInt() : x(0U) {} constexpr ModInt(unsigned x_) : x(x_ % M) {} constexpr ModInt(unsigned long long x_) : x(x_ % M) {} constexpr ModInt(int x_) : x(((x_ %= static_cast(M)) < 0) ? (x_ + static_cast(M)) : x_) {} constexpr ModInt(long long x_) : x(((x_ %= static_cast(M)) < 0) ? (x_ + static_cast(M)) : x_) {} ModInt &operator+=(const ModInt &a) { x = ((x += a.x) >= M) ? (x - M) : x; return *this; } ModInt &operator-=(const ModInt &a) { x = ((x -= a.x) >= M) ? (x + M) : x; return *this; } ModInt &operator*=(const ModInt &a) { x = (static_cast(x) * a.x) % M; return *this; } ModInt &operator/=(const ModInt &a) { return (*this *= a.inv()); } ModInt pow(long long e) const { if (e < 0) return inv().pow(-e); ModInt a = *this, b = 1U; for (; e; e >>= 1) { if (e & 1) b *= a; a *= a; } return b; } ModInt inv() const { unsigned a = M, b = x; int y = 0, z = 1; for (; b; ) { const unsigned q = a / b; const unsigned c = a - q * b; a = b; b = c; const int w = y - static_cast(q) * z; y = z; z = w; } assert(a == 1U); return ModInt(y); } ModInt operator+() const { return *this; } ModInt operator-() const { ModInt a; a.x = x ? (M - x) : 0U; return a; } ModInt operator+(const ModInt &a) const { return (ModInt(*this) += a); } ModInt operator-(const ModInt &a) const { return (ModInt(*this) -= a); } ModInt operator*(const ModInt &a) const { return (ModInt(*this) *= a); } ModInt operator/(const ModInt &a) const { return (ModInt(*this) /= a); } template friend ModInt operator+(T a, const ModInt &b) { return (ModInt(a) += b); } template friend ModInt operator-(T a, const ModInt &b) { return (ModInt(a) -= b); } template friend ModInt operator*(T a, const ModInt &b) { return (ModInt(a) *= b); } template friend ModInt operator/(T a, const ModInt &b) { return (ModInt(a) /= b); } explicit operator bool() const { return x; } bool operator==(const ModInt &a) const { return (x == a.x); } bool operator!=(const ModInt &a) const { return (x != a.x); } friend std::ostream &operator<<(std::ostream &os, const ModInt &a) { return os << a.x; } }; //////////////////////////////////////////////////////////////////////////////// constexpr unsigned MO = 998244353; using Mint = ModInt; // graph: tree, vertex lists, modified (parent removed, heavy child first) int N; vector> graph; vector par, sz; int zeit; vector dis, fin; vector head; void dfsSz(int u) { sz[u] = 1; for (const int v : graph[u]) { graph[v].erase(find(graph[v].begin(), graph[v].end(), u)); par[v] = u; dfsSz(v); sz[u] += sz[v]; } } void dfsHLD(int u) { dis[u] = zeit++; const int deg = graph[u].size(); if (deg > 0) { int vm = graph[u][0]; int jm = 0; for (int j = 1; j < deg; ++j) { const int v = graph[u][j]; if (sz[vm] < sz[v]) { vm = v; jm = j; } } swap(graph[u][0], graph[u][jm]); head[vm] = head[u]; dfsHLD(vm); for (int j = 1; j < deg; ++j) { const int v = graph[u][j]; head[v] = v; dfsHLD(v); } } fin[u] = zeit; } void runHLD(int rt) { par.assign(N, -1); sz.resize(N); zeit = 0; dis.resize(N); fin.resize(N); head.resize(N); dfsSz(rt); head[rt] = rt; dfsHLD(rt); } //////////////////////////////////////////////////////////////////////////////// int /*N,*/ Q; vector A, B; vector Z; // DFS, BFS vector X, Y; vector> ps; struct Node { // z -> c z + d int l, r; int pos0, pos1; bool isX; int x0, x1, y0, y1; Mint c, d; void push(Node &ll, Node &rr) { if (!(c == 1 && d == 0)) { ll.ch(c, d); rr.ch(c, d); c = 1; d = 0; } } void ch(Mint cc, Mint dd) { c = cc * c; d = cc * d + dd; } }; int nodesLen; vector nodes; int Build(int pos0, int pos1, bool isX) { const int u = nodesLen++; Node &f = nodes[u]; f.l = f.r = -1; f.pos0 = pos0; f.pos1 = pos1; f.isX = isX; f.c = 1; f.d = 0; f.x0 = N; f.x1 = -1; f.y0 = N; f.y1 = -1; for (int j = pos0; j < pos1; ++j) { chmin(f.x0, ps[j].first ); chmax(f.x1, ps[j].first ); chmin(f.y0, ps[j].second); chmax(f.y1, ps[j].second); } ++f.x1; ++f.y1; if (pos0 + 1 < pos1) { const int mid = (pos0 + pos1) / 2; if (isX) { nth_element(ps.begin() + pos0, ps.begin() + mid, ps.begin() + pos1, [&](const pair &p0, const pair &p1) -> bool { return (p0.first < p1.first ); }); } else { nth_element(ps.begin() + pos0, ps.begin() + mid, ps.begin() + pos1, [&](const pair &p0, const pair &p1) -> bool { return (p0.second < p1.second); }); } f.l = Build(pos0, mid, !isX); f.r = Build(mid, pos1, !isX); } // cerr< Get(int u, int x, int y) { Node &f = nodes[u]; if (!~f.l) { return make_pair(f.c, f.d); } else { f.push(nodes[f.l], nodes[f.r]); const Node &fl = nodes[f.l]; return Get((f.isX ? (x < fl.x1) : (y < fl.y1)) ? f.l : f.r, x, y); } } int main() { { sc.read(N, Q); A.resize(N - 1); B.resize(N - 1); for (int i = 0; i < N - 1; ++i) { sc.read(A[i], B[i]); --A[i]; --B[i]; } Z.resize(N); for (int u = 0; u < N; ++u) { sc.read(Z[u].x); } graph.assign(N, {}); for (int i = 0; i < N - 1; ++i) { graph[A[i]].push_back(B[i]); graph[B[i]].push_back(A[i]); } runHLD(0); X = dis; Y.assign(N, 0); vector dep(N, 0); vector>> layers(N); { int y = 0; queue que; que.push(0); for (; !que.empty(); ) { const int u = que.front(); que.pop(); Y[u] = y++; layers[dep[u]].emplace_back(X[u], u); for (const int v : graph[u]) { dep[v] = dep[u] + 1; que.push(v); } } } // cerr<<"graph = "< void { ++x1; Ch(0, x0, x1, 0, N, C, D); }; int u = U, v = V; for (; ; ) { if (head[u] == head[v]) { oper(min(dis[u], dis[v]), max(dis[u], dis[v])); break; } if (dep[head[u]] > dep[head[v]]) { oper(dis[head[u]], dis[u]); u = par[head[u]]; } else { oper(dis[head[v]], dis[v]); v = par[head[v]]; } } } break; default: assert(false); } } } return 0; }