#include using namespace std; template struct tree { struct edge { int u, v; T w; }; const int n; vector es; vector> g; vector pv, pe, sz, dep, vs, in, out, head; vector dist; tree(int _n = 0) : n(_n), g(n) {} void add_edge(int u, int v, T w = 1) { g[u].push_back(es.size()), g[v].push_back(es.size()); es.push_back({u, v, w}); } int other(int id, int v) { return es[id].u ^ es[id].v ^ v; } void dfs(int v) { sz[v] = 1; for (int& id : g[v]) { if (id == pe[v]) continue; int to = other(id, v); assert(pv[to] == -1); pv[to] = v, pe[to] = id; dep[to] = dep[v] + 1, dist[to] = dist[v] + es[id].w; dfs(to); sz[v] += sz[to]; if (g[v][0] == pv[v] or sz[to] > sz[other(g[v][0], v)]) swap(g[v][0], id); } } void build(int r = 0) { assert((int)es.size() == n - 1); pv.assign(n, -1), pe.resize(n), sz.resize(n), dep.resize(n), dist.resize(n); pe[r] = -1, dep[r] = 0, dist[r] = 0; dfs(r); } void dfs_hld(int v) { in[v] = vs.size(), vs.push_back(v); for (int id : g[v]) { if (id == pe[v]) continue; int to = other(id, v); head[to] = to == other(g[v][0], v) ? head[v] : to; dfs_hld(to); } out[v] = vs.size(); } void build_hld(int r = 0) { build(r); vs.clear(), in.resize(n), out.resize(n), head.resize(n); head[r] = r; dfs_hld(r); } bool anc(int u, int v) const { return in[u] <= in[v] and out[v] <= out[u]; } int lca(int u, int v) const { while (true) { if (in[u] > in[v]) swap(u, v); if (head[u] == head[v]) return u; v = pv[head[v]]; } } int la(int v, int d) const { assert(0 <= d and d <= dep[v]); while (dep[head[v]] > d) v = pv[head[v]]; return vs[in[head[v]] + (d - dep[head[v]])]; } int next(int from, int to) const { assert(from != to); if (not anc(from, to)) return pv[from]; return la(to, dep[from] + 1); } vector> ascend(int from, int to) const { assert(anc(to, from)); vector> res; while (head[from] != head[to]) { res.emplace_back(in[from], in[head[from]]); from = pv[head[from]]; } if (from != to) res.emplace_back(in[from], in[to] + 1); return res; } vector> descend(int from, int to) const { assert(anc(from, to)); if (from == to) return {}; if (head[from] == head[to]) return {{in[from] + 1, in[to]}}; auto res = descend(from, pv[head[to]]); res.emplace_back(in[head[to]], in[to]); return res; } template void run(int from, int to, F f, bool vertex = true) const { int v = lca(from, to); for (auto e : ascend(from, v)) f(e.first + 1, e.second); if (vertex) f(in[v], in[v] + 1); for (auto e : descend(v, to)) f(e.first, e.second + 1); } }; template > struct segtree { const Op op; const T e = T(); const int n = 0; vector t; T& operator[](int i) { return t[n + i]; } void build() { for (int i = n; i--; ) t[i] = op(t[2 * i], t[2 * i + 1]); } T fold(int l, int r) const { T a = e, b = e; for (l += n, r += n; l < r; l >>= 1, r >>= 1) { if (l & 1) a = op(a, t[l++]); if (r & 1) b = op(t[--r], b); } return op(a, b); } void set(int i, T a) { t[i += n] = a; while (i >>= 1) t[i] = op(t[2 * i], t[2 * i + 1]); } }; template auto make_segtree(int n, Op op, T e) { return segtree{op, e, n, vector(2 * n, e)}; } template struct modular { using m = modular; unsigned v; modular(long long x = 0) : v((x %= M) < 0 ? x + M : x) {} m operator-() const { return m() -= *this; } m& operator+=(m b) { if ((v += b.v) >= M) v -= M; return *this; } m& operator-=(m b) { if (v < b.v) v += M; v -= b.v; return *this; } m& operator*=(m b) { v = (uint64_t)v * b.v % M; return *this; } friend m operator+(m a, m b) { return a += b; } friend m operator-(m a, m b) { return a -= b; } friend m operator*(m a, m b) { return a *= b; } friend bool operator==(m a, m b) { return a.v == b.v; } friend string to_string(m a) { return to_string(a.v); } }; constexpr long long mod = 1e9 + 7; using mint = modular; using mat = array, 2>; mat operator*(const mat& a, const mat& b) { mat c; for (int i : {0, 1}) { for (int k : {0, 1}) { for (int j : {0, 1}) { c[i][j] += a[i][k] * b[k][j]; } } } return c; } int main() { cin.tie(nullptr); ios::sync_with_stdio(false); int n; cin >> n; tree g(n); for (int id = 0; id < n - 1; ++id) { int u, v; cin >> u >> v; g.add_edge(u, v); } g.build_hld(); mat e{1, 0, 0, 1}; auto st = make_segtree>(n, [](const auto& a, const auto& b) { return make_pair(a.first * b.first, b.second * a.second); }, {e, e}); int q; cin >> q; while (q--) { char c; cin >> c; if (c == 'x') { int id; cin >> id; int v = g.es[id].u; if (g.dep[v] < g.dep[g.es[id].v]) { v = g.es[id].v; } mat a; cin >> a[0][0].v >> a[0][1].v >> a[1][0].v >> a[1][1].v; st.set(g.in[v], {a, a}); } else { int u, v; cin >> u >> v; mat a = e; g.run(u, v, [&](int l, int r) { if (l < r) { a = a * st.fold(l, r).first; } else { a = a * st.fold(r, l).second; } }, false); cout << a[0][0].v << ' ' << a[0][1].v << ' ' << a[1][0].v << ' ' << a[1][1].v << '\n'; } } }