#include #define ll long long #define INF 1000000005 #define MOD 1000000007 #define EPS 1e-10 #define rep(i,n) for(int i=0;i<(int)(n);++i) #define rrep(i,n) for(int i=(int)(n)-1;i>=0;--i) #define srep(i,s,t) for(int i=(int)(s);i<(int)(t);++i) #define each(a,b) for(auto& (a): (b)) #define all(v) (v).begin(),(v).end() #define len(v) (int)(v).size() #define zip(v) sort(all(v)),v.erase(unique(all(v)),v.end()) #define cmx(x,y) x=max(x,y) #define cmn(x,y) x=min(x,y) #define fi first #define se second #define pb push_back #define show(x) cout<<#x<<" = "<<(x)< P; typedef pair pll; typedef vector vi; typedef vector vvi; typedef vector vl; typedef vector vvl; typedef vector vd; typedef vector

vp; typedef vector vs; const int MAX_N = 100005; template class mat : public vector > { private: int r,c; //行,列 public: int row() const { return r; } int column() const { return c; } mat(){} mat(int n,int m,T val = 0){ this->r = n,this->c = m; rep(i,n){ this->push_back(vector(m,val)); } } void Set(int n){ this->r = n,this->c = n; rep(i,n){ this->push_back(vector(n,0)); } rep(i,n){ (*this)[i][i] = 1; } } mat operator+(const mat& another){ if(this->r != another.r && this->c != another.c){ cout << "足し算失敗(サイズ不一致)" << endl; exit(1); } mat X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] + another[i][j]; } } return X; } mat operator+(const T val){ mat X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] + val; } } return X; } mat operator-(const mat& another){ if(this->r != another.r && this->c != another.c){ cout << "引き算失敗(サイズ不一致)" << endl; exit(1); } mat X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] - another[i][j]; } } return X; } mat operator-(const T val){ mat X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] - val; } } return X; } vector operator*(const vector& another){ if(this->c != (int)another.size()){ cout << "掛け算失敗(サイズ不一致)" << endl; exit(1); } vector vec(this->r,0); rep(i,this->r){ rep(j,this->c){ vec[i] += (*this)[i][j] * another[j]; } } return vec; } mat operator*(const mat& another){ if(this->c != another.r){ cout << "掛け算失敗(サイズ不一致)" << endl; exit(1); } mat X(this->r,another.c); rep(i,this->r){ rep(k,this->c){ rep(j,another.c){ X[i][j] = (X[i][j] + (*this)[i][k]*another[k][j]) % MOD; } } } return X; } mat operator-(){ mat X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = -(*this)[i][j]; } } return X; } void print(){ rep(i,this->r){ rep(j,(this->c)-1){ cout << (*this)[i][j] << ","; } cout << (*this)[i][(this->c)-1] << endl; } } }; struct HLdecomposition{ struct Centroid{ int parid, pardepth, depth, sz; //親のパスのid,親のノードは親のパスの何番目,パスの深さ,属する頂点の数 Centroid(int idx, int dep, int deep, int size) : parid(idx), pardepth(dep), depth(deep), sz(size){} P Up(){ return P(parid, pardepth); } }; vector > G; vector stsize, nxpath; vector pathorder, pathid; //何番目のパスに属するか,そのパスの何番目か vector centroids; //パスが格納 vector index; void Buildstsize(){ stack

s; s.push(P(0, -1)); while(!s.empty()) { P p = s.top(); s.pop(); if(stsize[p.first] != -1){ nxpath[p.first] = -1; for(int to : G[p.first]){ //親に向かう場合 if(p.second == to){ continue; } stsize[p.first] += stsize[to]; if(nxpath[p.first] == -1 || stsize[nxpath[p.first]] < stsize[to]) { nxpath[p.first] = to; } } }else{ s.push(p); stsize[p.first] = 1; for(int to : G[p.first]){ if(p.second != to){ s.push(P(to, p.first)); } } } } } void BuildPath() { stack

s; centroids.emplace_back(-1, -1, 0, 0); s.push(P(0, -1)); pathorder[0] = 0; while(!s.empty()) { P p = s.top(); s.pop(); pathid[p.first] = centroids[pathorder[p.first]].sz; for(int to : G[p.first]){ if(p.second == to) continue; if(to == nxpath[p.first]){ // Centroid-Pathについて pathorder[to] = pathorder[p.first]; }else{ // Centroid-Pathでないものについて pathorder[to] = (int)centroids.size(); centroids.emplace_back(pathorder[p.first], pathid[p.first], centroids[pathorder[p.first]].depth + 1,0); } s.emplace(to, p.first); } centroids[pathorder[p.first]].sz++; } } void Build_index(){ int ptr = 0; for(auto& centroid : centroids){ index.push_back(ptr); ptr += centroid.sz; } } void add_edge(int x, int y) { G[x].push_back(y), G[y].push_back(x); } void Build() { Buildstsize(); BuildPath(), Build_index(); } //idxが何番目のパスの何番目か P info(int idx) { return P(pathorder[idx], pathid[idx]); } //元の頂点のインデックスの配列上でのidを返す int get(int a) { P p = info(a); return (index[p.first] + p.second); } Centroid &operator[](int k) { return (centroids[k]); } void query(int a, int b, const function< void(int, int) > &func) { int pathidA, pathdepthA, pathidB, pathdepthB; tie(pathidA, pathdepthA) = info(a); tie(pathidB, pathdepthB) = info(b); while(pathidA != pathidB) { if(centroids[pathidA].depth > centroids[pathidB].depth) { func(index[pathidA], index[pathidA] + pathdepthA + 1); tie(pathidA, pathdepthA) = centroids[pathidA].Up(); }else{ func(index[pathidB], index[pathidB] + pathdepthB + 1); tie(pathidB, pathdepthB) = centroids[pathidB].Up(); } } if(pathdepthA > pathdepthB) swap(pathdepthA, pathdepthB); func(index[pathidA] + pathdepthA + 1, index[pathidA] + pathdepthB + 1); } HLdecomposition(int SZ) { G.resize(SZ); stsize.assign(SZ, -1); nxpath.resize(SZ); pathorder.resize(SZ); pathid.resize(SZ); } }; template class segtree { private: int n,sz; vector node; V I; public: segtree(int ag){ sz = ag; n = 1; while(n < sz){ n *= 2; } node.resize(2*n-1); rep(i,2*n-1){ node[i].Set(2); } I.Set(2); } void update(int k,V a) { k += n-1; node[k] = a; while(k>0){ k = (k-1)/2; node[k] = node[2*k+1] * node[2*k+2]; } } V query(int a,int b,int k=0,int l=0,int r=-1) { if(r < 0) r = n; if(r <= a || b <= l){ return I; } if(a <= l && r <= b){ return node[k]; }else{ V vl = query(a,b,2*k+1,l,(l+r)/2); V vr = query(a,b,2*k+2,(l+r)/2,r); return vl * vr; } } void print() { rep(i,sz){ cout << query(i,i+1) << " "; } cout << endl; } }; int depth[MAX_N]; void dfs(int u,int p,int d,HLdecomposition& hl) { vvi& G = hl.G; depth[u] = d; for(int v : G[u]){ if(v != p){ dfs(v,u,d+1,hl); } } } int get(int x,vp& eda) { int res; if(depth[eda[x].fi] < depth[eda[x].se]){ res = eda[x].se; }else{ res = eda[x].fi; } return res; } int main() { cin.tie(0); ios::sync_with_stdio(false); int n; cin >> n; HLdecomposition hl(n); vp eda(n-1); rep(i,n-1){ int a,b; cin >> a >> b; hl.add_edge(a,b); eda[i] = P(a,b); } hl.Build(); dfs(0,-1,0,hl); vi trans(n); rep(i,n){ trans[i] = hl.get(i); } int Q; cin >> Q; segtree > seg(n); rep(i,Q){ char a; cin >> a; if(a == 'x'){ int b,c,d,e,f; cin >> b >> c >> d >> e >> f; mat up(2,2); up[0][0] = c,up[0][1] = d,up[1][0] = e,up[1][1] = f; seg.update(trans[get(b,eda)],up); }else{ mat ans; ans.Set(2); int b,c; cin >> b >> c; hl.query(b, c, [&](int l, int r){ ans = seg.query(l, r) * ans; }); cout << ans[0][0] << " " << ans[0][1] << " " << ans[1][0] << " " << ans[1][1] << "\n"; } } }