//#define _GLIBCXX_DEBUG #include #define rep(i, n) for(int i=0; i; using vs = vector; using vi = vector; using vvi = vector; template using PQ = priority_queue; template using PQG = priority_queue, greater >; const int INF = 0xccccccc; const ll LINF = 0xcccccccccccccccLL; template inline bool chmax(T1 &a, T2 b) {return a < b && (a = b, true);} template inline bool chmin(T1 &a, T2 b) {return a > b && (a = b, true);} template istream &operator>>(istream &is, pair &p) { return is >> p.first >> p.second;} template ostream &operator<<(ostream &os, const pair &p) { return os << p.first << ' ' << p.second;} #undef _GLIBCXX_DEBUG string to_string(const string &s) {return '"' + s + '"';} string to_string(const char *s) {return to_string(string(s));} string to_string(bool b) {return b?"true":"false";} string to_string(vector v) { string res = "{"; for(int i = 0; i < int(v.size()); i++) { if(i) res += ", "; res += to_string(v[i]); } res += "}"; return res; } template string to_string(bitset v) { string res; for(size_t i = 0; i < N; i++) res += char('0' + v[i]); return res; } template string to_string(pair); template string to_string(tuple); template string to_string(tuple); template string to_string(A v) { bool first = true; string res = "{"; for(const auto &x:v) { if(!first) res += ", "; first = false; res += to_string(x); } res += "}"; return res; } template string to_string(pair p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; } template string to_string(tuple t) { return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " + to_string(get<2>(t)) + ")"; } template string to_string(tuple t) { return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " + to_string(get<2>(t)) + ", " + to_string(get<3>(t)) + ")"; } void debug_out() {cerr << endl;} template void debug_out(Head H, Tail... T) { cerr << ' ' << to_string(H); debug_out(T...); } #ifdef LOCAL #define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__) #else #define debug(...) 822 #endif const unsigned int mod = 1000000007; //const unsigned int mod = 998244353; struct mint { unsigned int x; mint():x(0) {} mint(int64_t x_) { int64_t v = int64_t(x_ % mod); if(v < 0) v += mod; x = (unsigned int)v; } static mint row(int v) { mint v_; v_.x = v; return v_; } mint operator-() const { return mint(-int64_t(x));} mint& operator+=(const mint a) { if ((x += a.x) >= mod) x -= mod; return *this; } mint& operator-=(const mint a) { if ((x += mod-a.x) >= mod) x -= mod; return *this; } mint& operator*=(const mint a) { uint64_t z = x; z *= a.x; x = (unsigned int)(z % mod); return *this; } mint operator+(const mint a) const { return mint(*this) += a;} mint operator-(const mint a) const { return mint(*this) -= a;} mint operator*(const mint a) const { return mint(*this) *= a;} friend bool operator==(const mint &a, const mint &b) {return a.x == b.x;} friend bool operator!=(const mint &a, const mint &b) {return a.x != b.x;} mint &operator++() { x++; if(x == mod) x = 0; return *this; } mint &operator--() { if(x == 0) x = mod; x--; return *this; } mint operator++(int) { mint result = *this; ++*this; return result; } mint operator--(int) { mint result = *this; --*this; return result; } mint pow(int64_t t) const { mint x_ = *this, r = 1; while(t) { if(t&1) r *= x_; x_ *= x_; t >>= 1; } return r; } //for prime mod mint inv() const { return pow(mod-2);} mint& operator/=(const mint a) { return *this *= a.inv();} mint operator/(const mint a) {return mint(*this) /= a;} }; istream& operator>>(istream& is, mint& a) { return is >> a.x;} ostream& operator<<(ostream& os, const mint& a) { return os << a.x;} template struct SegTree { using FX = function; int n, _n; FX fx; const T ex; vector dat; SegTree(int n_, FX fx_, T ex_):fx(fx_), ex(ex_), n(1), _n(n_) { while(n < n_) n <<= 1; dat.assign((n<<1)-1, ex); } SegTree(vector &v, FX fx_, T ex_):fx(fx_), ex(ex_), n(1), _n(int(v.size())) { while(n < _n) n <<= 1; dat.assign((n<<1)-1, ex); copy(v.begin(), v.end(), dat.begin()+n-1); build(); } inline int chld(int k) {return (k<<1)+1;} inline int chrd(int k) {return (k<<1)+2;} void set(int i, T t) {dat[i+n-1] = t;} void build() { for(int k = n-2; k >= 0; k--) dat[k] = fx(dat[chld(k)], dat[chrd(k)]); } void update(int i, T x) { i += n-1; dat[i] = x; while(i) { i = (i-1)>>1; dat[i] = fx(dat[chld(i)], dat[chrd(i)]); } } inline T query(int a, int b) {return query(a, b, 0, 0, n);} T query(int a, int b, int k, int l, int r) { if(r <= a || b <= l) return ex; if(a <= l && r <= b) return dat[k]; T vl = query(a, b, chld(k), l, (l+r)>>1); T vr = query(a, b, chrd(k), (l+r)>>1, r); return fx(vl, vr); } template int max_right(int l, F f) { assert(f(ex)); if(l == _n) return _n; l += n; T now = ex; do { while(~l&1) l >>= 1; if(!f(fx(now, dat[l-1]))) { while(l < n) { l <<= 1; if(f(fx(now, dat[l-1]))) { now = fx(now, dat[l++ - 1]); } } return l-n; } now = fx(now, dat[l++ - 1]); } while((l & -l) != l); return _n; } template int min_left(int r, F f) { assert(f(ex)); if(r == 0) return 0; r += n; T now = ex; do { r--; while(r > 1 and r&1) r >>= 1; if(!f(fx(dat[r-1], now))) { while(r < n) { r = chld(r); if(f(fx(dat[r-1], now))) { now = fx(dat[--r], now); } } return r+1-n; } now = fx(dat[r-1], now); } while((r & -r) != r); return 0; } const T &operator[](int idx) const {return dat[idx+n-1];} }; struct HLD { using Graph = vector>; using F = function; Graph G; vector parent, heavy, depth, root, ids, sub, type, inv; int _n; HLD() {} HLD(int n):G(n), parent(n, -1), heavy(n, -1), depth(n), root(n, -1), ids(n), _n(n), sub(n, 1), type(n), inv(n) {} void add(int i, int j) { G[i].emplace_back(j); G[j].emplace_back(i); } void init(vector roots = vector(1, 0)) { int group = 0; int pos = 0; for(int rt:roots) { dfs(rt); bfs(rt, group++, pos); } } void dfs(int rt) { stack> st; st.emplace(rt, 0); while(!st.empty()) { int v = st.top().first; int &siz = st.top().second; if(siz < int(G[v].size())) { int u = G[v][siz++]; if(u == parent[v]) continue; parent[u] = v; depth[u] = depth[v]+1; st.emplace(u, 0); } else { st.pop(); int maxSubtree = 0; for(int u:G[v]) { if(u == parent[v]) continue; sub[v] += sub[u]; if(maxSubtree < sub[u]) maxSubtree = sub[u], heavy[v] = u; } } } } void bfs(int rt, int group, int &pos) { queue que({rt}); while(!que.empty()) { int v = que.front(); que.pop(); for(int u = v; u != -1; u = heavy[u]) { type[u] = group; ids[u] = pos++; inv[ids[u]] = u; root[u] = v; for(int w:G[u]) { if(w != parent[u] and w != heavy[u]) que.emplace(w); } } } } //edge = false -> for_each_vertex, edge = true -> for_each_edge void for_each(int u, int v, const F &f, bool edge = false) { assert(type[u] == type[v]); while(true) { if(ids[u] > ids[v]) swap(u, v); if(root[u] == root[v]) { if(edge) { if(u != v) f(ids[u]+1, ids[v]+1); } else f(ids[u], ids[v]+1); break; } f(ids[root[v]], ids[v]+1); v = parent[root[v]]; } } int lca(int u, int v) { while(true) { if(ids[u] > ids[v]) swap(u, v); if(root[u] == root[v]) return u; v = parent[root[v]]; } } int dis(int u, int v) { return depth[u] + depth[v] - (depth[lca(u, v)]<<1); } const int &operator[](int i) const {return ids[i];} }; //head struct M { array, 2> x; M() {} M(mint i) { x[0][0] = x[1][1] = i; } M(mint a, mint b, mint c, mint d) { x[0][0] = a; x[0][1] = b; x[1][0] = c; x[1][1] = d; } M mul(const M &u) { M res; rep(i, 2) rep(j, 2) rep(k, 2) res[i][j] += x[i][k]*u[k][j]; return res; } array &operator[](int i) {return x[i];} const array &operator[](int i) const {return x[i];} }; ostream &operator<<(ostream &os, const M &res) {return os << res[0][0] << ' ' << res[0][1] << ' ' << res[1][0] << ' ' << res[1][1] << '\n';} int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; vector

ab(n-1); HLD hld(n); rep(i, n-1) { int a, b; cin >> a >> b; ab[i] = {a, b}; hld.add(a, b); } hld.init(); SegTree seg(n, [](M a, M b)->M{return a.mul(b);}, M(1)); int q; cin >> q; while(q--) { char c; cin >> c; if(c == 'x') { int id; mint a, b, c, d; cin >> id >> a >> b >> c >> d; auto [u, v] = ab[id]; u = hld[u]; v = hld[v]; seg.update(max(u, v), M(a, b, c, d)); debug(ab[id]); } else { int i, j; cin >> i >> j; M res(1); hld.for_each(i, j, [&](int i, int j)->void{res = seg.query(i, j).mul(res);}, true); cout << res; } } }