// #pragma GCC optimize("Ofast") #include using namespace std; using ll = long long; using ull = unsigned long long; using vecint = std::vector; using vecll = std::vector; using vecstr = std::vector; using vecbool = std::vector; using vecdou = std::vector; using vecpl = std::vector>; using vec2d = std::vector; using vec2di = std::vector; using vec2dd = std::vector; using vec2db = std::vector; using pl = pair; #define rep(i,n) for (ll i = 0; i < (ll)(n); i++) #define rep1(i,n) for (ll i = 1; i <= (ll)(n); i++) #define REP(i,l,r) for (ll i = (ll)(l); i < (ll)(r); i++) #define rrep(i,n) for (ll i = (ll)(n)-1; i >= 0; i--) #define rrep1(i,n) for (ll i = (ll)(n); i > 0; i--) #define RREP(i,l,r) for (ll i = (ll)(r)-1; i >= (ll)(l); i--) #define all(a) (a).begin(), (a).end() #define INF ((1LL<<62)-(1LL<<31)) #define inr(a,x,b) ((a) <= (x) && (x) < (b)) template bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; } template bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; } void ynout(bool x,string Tru="Yes",string Wro="No"){ if(x){ cout << Tru << '\n'; }else{ cout << Wro << '\n'; } } ll power(ll a,ll b,ll mod=INF){ long long x=1,y=a%mod; while(b>0){ if(b&1ll){ x=(x*y)%mod; } y=(y*y)%mod; b>>=1; } return x%mod; } ll Pdist2(pair a,pair b){ return (a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second); } double Pdist(pair a,pair b){ return sqrt(Pdist2(a,b)); } ll PdistM(pair a,pair b){ return abs(a.first-b.first)+abs(a.second-b.second); } ll gcd(ll a,ll b){ if(b==0){ return a; }else{ return gcd(b,a%b); } } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } template void print(const std::vector& v) { for (const auto& elem : v) { cout << elem << " "; } cout << '\n'; } template void print2d(const std::vector>& v) { for (const auto& row : v) { for (const auto& elem : row) { cout << elem << " "; } cout << '\n'; } } vecll vecinp(ll n){ vecll v(n); rep(i,n) cin >> v[i]; return v; } void solve(); int main() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); ll t=1; // std::cin >> t; rep(i,t)solve(); } // vecll dx = {1,0,-1,0}; // vecll dy = {0,1,0,-1}; // vector dir = {'D','R','U','L'}; // begin include: atcoder/modint // begin include: atcoder/modint.hpp #include #include #include #ifdef _MSC_VER #include #endif // begin include: atcoder/internal_math // begin include: atcoder/internal_math.hpp #include #ifdef _MSC_VER #include #endif namespace atcoder { namespace internal { // @param m `1 <= m` // @return x mod m constexpr long long safe_mod(long long x, long long m) { x %= m; if (x < 0) x += m; return x; } // Fast modular multiplication by barrett reduction // Reference: https://en.wikipedia.org/wiki/Barrett_reduction // NOTE: reconsider after Ice Lake struct barrett { unsigned int _m; unsigned long long im; // @param m `1 <= m` explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {} // @return m unsigned int umod() const { return _m; } // @param a `0 <= a < m` // @param b `0 <= b < m` // @return `a * b % m` unsigned int mul(unsigned int a, unsigned int b) const { // [1] m = 1 // a = b = im = 0, so okay // [2] m >= 2 // im = ceil(2^64 / m) // -> im * m = 2^64 + r (0 <= r < m) // let z = a*b = c*m + d (0 <= c, d < m) // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2 // ((ab * im) >> 64) == c or c + 1 unsigned long long z = a; z *= b; #ifdef _MSC_VER unsigned long long x; _umul128(z, im, &x); #else unsigned long long x = (unsigned long long)(((unsigned __int128)(z)*im) >> 64); #endif unsigned long long y = x * _m; return (unsigned int)(z - y + (z < y ? _m : 0)); } }; // @param n `0 <= n` // @param m `1 <= m` // @return `(x ** n) % m` constexpr long long pow_mod_constexpr(long long x, long long n, int m) { if (m == 1) return 0; unsigned int _m = (unsigned int)(m); unsigned long long r = 1; unsigned long long y = safe_mod(x, m); while (n) { if (n & 1) r = (r * y) % _m; y = (y * y) % _m; n >>= 1; } return r; } // Reference: // M. Forisek and J. Jancina, // Fast Primality Testing for Integers That Fit into a Machine Word // @param n `0 <= n` constexpr bool is_prime_constexpr(int n) { if (n <= 1) return false; if (n == 2 || n == 7 || n == 61) return true; if (n % 2 == 0) return false; long long d = n - 1; while (d % 2 == 0) d /= 2; constexpr long long bases[3] = {2, 7, 61}; for (long long a : bases) { long long t = d; long long y = pow_mod_constexpr(a, t, n); while (t != n - 1 && y != 1 && y != n - 1) { y = y * y % n; t <<= 1; } if (y != n - 1 && t % 2 == 0) { return false; } } return true; } template constexpr bool is_prime = is_prime_constexpr(n); // @param b `1 <= b` // @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g constexpr std::pair inv_gcd(long long a, long long b) { a = safe_mod(a, b); if (a == 0) return {b, 0}; // Contracts: // [1] s - m0 * a = 0 (mod b) // [2] t - m1 * a = 0 (mod b) // [3] s * |m1| + t * |m0| <= b long long s = b, t = a; long long m0 = 0, m1 = 1; while (t) { long long u = s / t; s -= t * u; m0 -= m1 * u; // |m1 * u| <= |m1| * s <= b // [3]: // (s - t * u) * |m1| + t * |m0 - m1 * u| // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u) // = s * |m1| + t * |m0| <= b auto tmp = s; s = t; t = tmp; tmp = m0; m0 = m1; m1 = tmp; } // by [3]: |m0| <= b/g // by g != b: |m0| < b/g if (m0 < 0) m0 += b / s; return {s, m0}; } // Compile time primitive root // @param m must be prime // @return primitive root (and minimum in now) constexpr int primitive_root_constexpr(int m) { if (m == 2) return 1; if (m == 167772161) return 3; if (m == 469762049) return 3; if (m == 754974721) return 11; if (m == 998244353) return 3; int divs[20] = {}; divs[0] = 2; int cnt = 1; int x = (m - 1) / 2; while (x % 2 == 0) x /= 2; for (int i = 3; (long long)(i)*i <= x; i += 2) { if (x % i == 0) { divs[cnt++] = i; while (x % i == 0) { x /= i; } } } if (x > 1) { divs[cnt++] = x; } for (int g = 2;; g++) { bool ok = true; for (int i = 0; i < cnt; i++) { if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if (ok) return g; } } template constexpr int primitive_root = primitive_root_constexpr(m); // @param n `n < 2^32` // @param m `1 <= m < 2^32` // @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64) unsigned long long floor_sum_unsigned(unsigned long long n, unsigned long long m, unsigned long long a, unsigned long long b) { unsigned long long ans = 0; while (true) { if (a >= m) { ans += n * (n - 1) / 2 * (a / m); a %= m; } if (b >= m) { ans += n * (b / m); b %= m; } unsigned long long y_max = a * n + b; if (y_max < m) break; // y_max < m * (n + 1) // floor(y_max / m) <= n n = (unsigned long long)(y_max / m); b = (unsigned long long)(y_max % m); std::swap(m, a); } return ans; } } // namespace internal } // namespace atcoder // end include: atcoder/internal_math.hpp // end include: atcoder/internal_math // begin include: atcoder/internal_type_traits // begin include: atcoder/internal_type_traits.hpp #include #include #include namespace atcoder { namespace internal { #ifndef _MSC_VER template using is_signed_int128 = typename std::conditional::value || std::is_same::value, std::true_type, std::false_type>::type; template using is_unsigned_int128 = typename std::conditional::value || std::is_same::value, std::true_type, std::false_type>::type; template using make_unsigned_int128 = typename std::conditional::value, __uint128_t, unsigned __int128>; template using is_integral = typename std::conditional::value || is_signed_int128::value || is_unsigned_int128::value, std::true_type, std::false_type>::type; template using is_signed_int = typename std::conditional<(is_integral::value && std::is_signed::value) || is_signed_int128::value, std::true_type, std::false_type>::type; template using is_unsigned_int = typename std::conditional<(is_integral::value && std::is_unsigned::value) || is_unsigned_int128::value, std::true_type, std::false_type>::type; template using to_unsigned = typename std::conditional< is_signed_int128::value, make_unsigned_int128, typename std::conditional::value, std::make_unsigned, std::common_type>::type>::type; #else template using is_integral = typename std::is_integral; template using is_signed_int = typename std::conditional::value && std::is_signed::value, std::true_type, std::false_type>::type; template using is_unsigned_int = typename std::conditional::value && std::is_unsigned::value, std::true_type, std::false_type>::type; template using to_unsigned = typename std::conditional::value, std::make_unsigned, std::common_type>::type; #endif template using is_signed_int_t = std::enable_if_t::value>; template using is_unsigned_int_t = std::enable_if_t::value>; template using to_unsigned_t = typename to_unsigned::type; } // namespace internal } // namespace atcoder // end include: atcoder/internal_type_traits.hpp // end include: atcoder/internal_type_traits namespace atcoder { namespace internal { struct modint_base {}; struct static_modint_base : modint_base {}; template using is_modint = std::is_base_of; template using is_modint_t = std::enable_if_t::value>; } // namespace internal template * = nullptr> struct static_modint : internal::static_modint_base { using mint = static_modint; public: static constexpr int mod() { return m; } static mint raw(int v) { mint x; x._v = v; return x; } static_modint() : _v(0) {} template * = nullptr> static_modint(T v) { long long x = (long long)(v % (long long)(umod())); if (x < 0) x += umod(); _v = (unsigned int)(x); } template * = nullptr> static_modint(T v) { _v = (unsigned int)(v % umod()); } unsigned int val() const { return _v; } mint& operator++() { _v++; if (_v == umod()) _v = 0; return *this; } mint& operator--() { if (_v == 0) _v = umod(); _v--; return *this; } mint operator++(int) { mint result = *this; ++*this; return result; } mint operator--(int) { mint result = *this; --*this; return result; } mint& operator+=(const mint& rhs) { _v += rhs._v; if (_v >= umod()) _v -= umod(); return *this; } mint& operator-=(const mint& rhs) { _v -= rhs._v; if (_v >= umod()) _v += umod(); return *this; } mint& operator*=(const mint& rhs) { unsigned long long z = _v; z *= rhs._v; _v = (unsigned int)(z % umod()); return *this; } mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); } mint operator+() const { return *this; } mint operator-() const { return mint() - *this; } mint pow(long long n) const { assert(0 <= n); mint x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; } mint inv() const { if (prime) { assert(_v); return pow(umod() - 2); } else { auto eg = internal::inv_gcd(_v, m); assert(eg.first == 1); return eg.second; } } friend mint operator+(const mint& lhs, const mint& rhs) { return mint(lhs) += rhs; } friend mint operator-(const mint& lhs, const mint& rhs) { return mint(lhs) -= rhs; } friend mint operator*(const mint& lhs, const mint& rhs) { return mint(lhs) *= rhs; } friend mint operator/(const mint& lhs, const mint& rhs) { return mint(lhs) /= rhs; } friend bool operator==(const mint& lhs, const mint& rhs) { return lhs._v == rhs._v; } friend bool operator!=(const mint& lhs, const mint& rhs) { return lhs._v != rhs._v; } private: unsigned int _v; static constexpr unsigned int umod() { return m; } static constexpr bool prime = internal::is_prime; }; template struct dynamic_modint : internal::modint_base { using mint = dynamic_modint; public: static int mod() { return (int)(bt.umod()); } static void set_mod(int m) { assert(1 <= m); bt = internal::barrett(m); } static mint raw(int v) { mint x; x._v = v; return x; } dynamic_modint() : _v(0) {} template * = nullptr> dynamic_modint(T v) { long long x = (long long)(v % (long long)(mod())); if (x < 0) x += mod(); _v = (unsigned int)(x); } template * = nullptr> dynamic_modint(T v) { _v = (unsigned int)(v % mod()); } unsigned int val() const { return _v; } mint& operator++() { _v++; if (_v == umod()) _v = 0; return *this; } mint& operator--() { if (_v == 0) _v = umod(); _v--; return *this; } mint operator++(int) { mint result = *this; ++*this; return result; } mint operator--(int) { mint result = *this; --*this; return result; } mint& operator+=(const mint& rhs) { _v += rhs._v; if (_v >= umod()) _v -= umod(); return *this; } mint& operator-=(const mint& rhs) { _v += mod() - rhs._v; if (_v >= umod()) _v -= umod(); return *this; } mint& operator*=(const mint& rhs) { _v = bt.mul(_v, rhs._v); return *this; } mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); } mint operator+() const { return *this; } mint operator-() const { return mint() - *this; } mint pow(long long n) const { assert(0 <= n); mint x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; } mint inv() const { auto eg = internal::inv_gcd(_v, mod()); assert(eg.first == 1); return eg.second; } friend mint operator+(const mint& lhs, const mint& rhs) { return mint(lhs) += rhs; } friend mint operator-(const mint& lhs, const mint& rhs) { return mint(lhs) -= rhs; } friend mint operator*(const mint& lhs, const mint& rhs) { return mint(lhs) *= rhs; } friend mint operator/(const mint& lhs, const mint& rhs) { return mint(lhs) /= rhs; } friend bool operator==(const mint& lhs, const mint& rhs) { return lhs._v == rhs._v; } friend bool operator!=(const mint& lhs, const mint& rhs) { return lhs._v != rhs._v; } private: unsigned int _v; static internal::barrett bt; static unsigned int umod() { return bt.umod(); } }; template internal::barrett dynamic_modint::bt(998244353); using modint998244353 = static_modint<998244353>; using modint1000000007 = static_modint<1000000007>; using modint = dynamic_modint<-1>; namespace internal { template using is_static_modint = std::is_base_of; template using is_static_modint_t = std::enable_if_t::value>; template struct is_dynamic_modint : public std::false_type {}; template struct is_dynamic_modint> : public std::true_type {}; template using is_dynamic_modint_t = std::enable_if_t::value>; } // namespace internal } // namespace atcoder // end include: atcoder/modint.hpp // end include: atcoder/modint // begin include: libraries/HLD_seg_edge.hpp #include // begin include: atcoder/segtree // begin include: atcoder/segtree.hpp #include #include #include #include // begin include: atcoder/internal_bit // begin include: atcoder/internal_bit.hpp #ifdef _MSC_VER #include #endif #if __cplusplus >= 202002L #include #endif namespace atcoder { namespace internal { #if __cplusplus >= 202002L using std::bit_ceil; #else // @return same with std::bit::bit_ceil unsigned int bit_ceil(unsigned int n) { unsigned int x = 1; while (x < (unsigned int)(n)) x *= 2; return x; } #endif // @param n `1 <= n` // @return same with std::bit::countr_zero int countr_zero(unsigned int n) { #ifdef _MSC_VER unsigned long index; _BitScanForward(&index, n); return index; #else return __builtin_ctz(n); #endif } // @param n `1 <= n` // @return same with std::bit::countr_zero constexpr int countr_zero_constexpr(unsigned int n) { int x = 0; while (!(n & (1 << x))) x++; return x; } } // namespace internal } // namespace atcoder // end include: atcoder/internal_bit.hpp // end include: atcoder/internal_bit namespace atcoder { #if __cplusplus >= 201703L template struct segtree { static_assert(std::is_convertible_v>, "op must work as S(S, S)"); static_assert(std::is_convertible_v>, "e must work as S()"); #else template struct segtree { #endif public: segtree() : segtree(0) {} explicit segtree(int n) : segtree(std::vector(n, e())) {} explicit segtree(const std::vector& v) : _n(int(v.size())) { size = (int)internal::bit_ceil((unsigned int)(_n)); log = internal::countr_zero((unsigned int)size); d = std::vector(2 * size, e()); for (int i = 0; i < _n; i++) d[size + i] = v[i]; for (int i = size - 1; i >= 1; i--) { update(i); } } void set(int p, S x) { assert(0 <= p && p < _n); p += size; d[p] = x; for (int i = 1; i <= log; i++) update(p >> i); } S get(int p) const { assert(0 <= p && p < _n); return d[p + size]; } S prod(int l, int r) const { assert(0 <= l && l <= r && r <= _n); S sml = e(), smr = e(); l += size; r += size; while (l < r) { if (l & 1) sml = op(sml, d[l++]); if (r & 1) smr = op(d[--r], smr); l >>= 1; r >>= 1; } return op(sml, smr); } S all_prod() const { return d[1]; } template int max_right(int l) const { return max_right(l, [](S x) { return f(x); }); } template int max_right(int l, F f) const { assert(0 <= l && l <= _n); assert(f(e())); if (l == _n) return _n; l += size; S sm = e(); do { while (l % 2 == 0) l >>= 1; if (!f(op(sm, d[l]))) { while (l < size) { l = (2 * l); if (f(op(sm, d[l]))) { sm = op(sm, d[l]); l++; } } return l - size; } sm = op(sm, d[l]); l++; } while ((l & -l) != l); return _n; } template int min_left(int r) const { return min_left(r, [](S x) { return f(x); }); } template int min_left(int r, F f) const { assert(0 <= r && r <= _n); assert(f(e())); if (r == 0) return 0; r += size; S sm = e(); do { r--; while (r > 1 && (r % 2)) r >>= 1; if (!f(op(d[r], sm))) { while (r < size) { r = (2 * r + 1); if (f(op(d[r], sm))) { sm = op(d[r], sm); r--; } } return r + 1 - size; } sm = op(d[r], sm); } while ((r & -r) != r); return 0; } private: int _n, size, log; std::vector d; void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); } }; } // namespace atcoder // end include: atcoder/segtree.hpp // end include: atcoder/segtree // begin include: edge.hpp template struct edge { int from, to; S weight; edge(int from_, int to_, S weight_) : from(from_), to(to_), weight(weight_) {} edge() : from(-1), to(-1), weight() {} }; // end include: edge.hpp using namespace std; using ll = long long; using vecll = std::vector; #define rep(i,n) for (ll i = 0; i < (ll)(n); i++) template struct HLD_seg_edge { vecll vertex; vecll id; vecll head; vecll parent; vecll depth; vecll subsize; vecll heavy_child; int root; static S op_rev(S a, S b) { return op(b, a); } atcoder::segtree seg; atcoder::segtree seg_rev; vecll edge_id; HLD_seg_edge(int n, const vector>& edges, int root_ = 0) { root = root_; vertex.resize(n); id.resize(n); head.resize(n); parent.resize(n); depth.resize(n); subsize.resize(n); heavy_child.resize(n); seg = atcoder::segtree(n); seg_rev = atcoder::segtree(n); edge_id.resize(n-1); vector> graph(n); for (const auto& edge : edges) { int u = edge.from, v = edge.to; graph[u].emplace_back(v); graph[v].emplace_back(u); } { function dfs = [&](int v, int p, int d) { parent[v] = p; depth[v] = d; subsize[v] = 1; heavy_child[v] = -1; int max_subsize = 0; for (int to : graph[v]) { if (to == p) continue; dfs(to, v, d + 1); subsize[v] += subsize[to]; if (subsize[to] > max_subsize) { max_subsize = subsize[to]; heavy_child[v] = to; } } }; dfs(root, -1, 0); } { int idx = 0; function dfs = [&](int v, int h) { head[v] = h; id[v] = idx; vertex[idx] = v; idx++; if (heavy_child[v] != -1) { dfs(heavy_child[v], h); } for (int to : graph[v]) { if (to == parent[v] || to == heavy_child[v]) continue; dfs(to, to); } }; dfs(root, root); } rep(i,edges.size()) { const auto& edge = edges[i]; int u = edge.from, v = edge.to; S w = edge.weight; if (parent[v] == u) { seg.set(id[v], w); seg_rev.set(id[v], w); edge_id[i] = id[v]; } else { seg.set(id[u], w); seg_rev.set(id[u], w); edge_id[i] = id[u]; } } } // vの祖先で深さがdのものを返す int level_ancestor(int v, int d) { if (depth[v] < d) return -1; while (depth[head[v]] > d) { v = parent[head[v]]; } return vertex[id[v] - (depth[v] - d)]; } // uとvのLCAを返す int lca(int u, int v) { while (head[u] != head[v]) { if (depth[head[u]] > depth[head[v]]) { u = parent[head[u]]; } else { v = parent[head[v]]; } } return depth[u] < depth[v] ? u : v; } // uとvの距離を返す int distance(int u, int v) { int l = lca(u, v); return depth[u] + depth[v] - 2 * depth[l]; } // s->tのパス上i番目の頂点を返す int jump(int s, int t, int i) { int l = lca(s, t); if (i <= depth[s] - depth[l]) { return level_ancestor(s, depth[s] - i); } else { return level_ancestor(t, i - depth[s] + 2*depth[l]); } } // 辺vの値をxに更新 void set(int v, S x) { seg.set(edge_id[v], x); seg_rev.set(edge_id[v], x); } S get(int i) { return seg.get(edge_id[i]); } // s->tのパス(e0,...,ek)に対し、e0・...・ekを返す S prod_path(int s, int t) { int l = lca(s, t); S res_left = e(), res_right = e(); while (head[s] != head[l]) { res_left = op(res_left, seg_rev.prod(id[head[s]], id[s] + 1)); s = parent[head[s]]; } res_left = op(res_left, seg_rev.prod(id[l] + 1, id[s] + 1)); while (head[t] != head[l]) { res_right = op(seg.prod(id[head[t]], id[t] + 1), res_right); t = parent[head[t]]; } res_right = op(seg.prod(id[l] + 1, id[t] + 1), res_right); return op(res_left, res_right); } }; // end include: libraries/HLD_seg_edge.hpp using S = vector>; S op(S a, S b) { int n = 2; S res(n, vector(n, 0)); rep(i,n)rep(j,n)rep(k,n){ res[i][j] += a[i][k] * b[k][j]; } return res; } S e() { int n = 2; S res(n, vector(n, 0)); rep(i,n) res[i][i] = 1; return res; } void solve(){ ll n; cin>>n; vector> E(n-1); rep(i,n-1){ ll u,v; cin>>u>>v; E[i] = edge(u, v, e()); } HLD_seg_edge hld(n, E); ll q; cin>>q; while(q--){ char t; cin>>t; if(t=='x'){ ll i; S x(2, vector(2)); cin>>i; rep(a,2)rep(b,2){ int val; cin>>val; x[a][b] = val; } hld.set(i,x); }else { ll u,v; cin>>u>>v; auto res = hld.prod_path(u,v); rep(i,2){ rep(j,2) cout << res[i][j].val() << " "; } cout << '\n'; } } }