#include using namespace std; using i64=int64_t; #define rep(i,x,y) for(i64 i=i64(x),i##_max_for_repmacro=i64(y); i ostream &operator<<(ostream &os, const vector &vec){ os << "["; for (const auto &v : vec) { os << v << ","; } os << "]"; return os; } template struct HeavyLightDecomposer{ const vector> graph; const int root,n; vector parent,subtree_size,depth, first,last,prev,next,path_id,local_index; vector> paths,children; vector segments; //pathに乗っけるデータ構造用 vector connections; //pathとpathを接続する辺に対応する HeavyLightDecomposer(const vector> &graph,int root):graph(graph),root(root),n(graph.size()), parent(n),subtree_size(n,1),depth(n),first(n),last(n),prev(n,-1),next(n,-1),path_id(n),local_index(n) { preprocess(); decompose(); segments.resize(paths.size()); connections.resize(paths.size()); } void preprocess(){ stack> dfs_stack; dfs_stack.push(make_tuple(root,-1,0)); while(!dfs_stack.empty()){ auto t=dfs_stack.top(); dfs_stack.pop(); int v=get<0>(t),p=get<1>(t),i=get<2>(t); if(i==0){ if(v!=root) depth[v]=depth[p]+1; dfs_stack.push(make_tuple(v,p,1)); for(int u:graph[v]){ if(u==p) continue; dfs_stack.push(make_tuple(u,v,0)); } }else{ parent[v]=p; for(int u:graph[v]){ if(u==p) continue; subtree_size[v]+=subtree_size[u]; } } } } using pii=pair; void decompose(){ int cnt=0; stack dfs_stack; dfs_stack.push(make_pair(root,0)); while(!dfs_stack.empty()){ auto p=dfs_stack.top(); dfs_stack.pop(); int v=p.first,id=p.second; if(paths.size()<=cnt) paths.resize(cnt+1); if(children.size()<=cnt) children.resize(cnt+1); int cur=v; while(cur!=-1){ paths[id].push_back(cur); int heavy_edge=-1; for(int u:graph[cur]){ if(u==parent[cur]) continue; if(heavy_edge==-1 and subtree_size[u]*2>=subtree_size[cur]-1) heavy_edge=u; else{ ++cnt; children[id].push_back(cnt); dfs_stack.push(make_pair(u,cnt)); } } cur=heavy_edge; } for(int i=0; i1){ int m=(lb+ub)/2; if(local_index[go_up(paths[children[path_id][m]].front())]>=idx) ub=m; else lb=m; } return ub; }; }; template class segtree{ public: int n,size_; vector dat; T id_; segtree()=default; segtree(int size,T id,T initial_value){ init(size,id,initial_value); } void init(int size,T id,T initial_value){ size_=size; id_=id; n=1; while(n0) { k=(k-1)/2; dat[k]=op(dat[k*2+1],dat[k*2+2]); } } T at(int index){ return dat[index+n-1]; } void add(int k,T a){ update(k,at(k)+a); } 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 or b<=l) return id_; if(a<=l and r<=b) return dat[k]; int m=(l+r)/2; return op(query(a,b,k*2+1,l,m),query(a,b,k*2+2,m,r)); } }; template class Fp{ public: i64 x; Fp():x(0){} Fp(i64 x_):x((x_%p+p)%p){} Fp operator+()const{ return Fp(x); } Fp operator-()const{ return Fp(-x); } Fp& operator+=(const Fp& y){ x=((x+y.x)%p+p)%p; return *this ;} Fp& operator-=(const Fp& y){ return *this+=-y; } Fp& operator*=(const Fp& y){ x=x*y.x%p; return *this; } Fp& operator/=(const Fp& y){ return *this*=Fp(inverse(y.x)); } Fp operator+(const Fp& y)const{ return Fp(x)+=y; } Fp operator-(const Fp& y)const{ return Fp(x)-=y; } Fp operator*(const Fp& y)const{ return Fp(x)*=y; } Fp operator/(const Fp& y)const{ return Fp(x)/=y; } bool operator==(const Fp& y)const{ return x==y.x; } bool operator!=(const Fp& y)const{ return !(*this==y); } i64 extgcd(i64 a,i64 b,i64 &x,i64 &y){ i64 d=a; if(b!=0){ d=extgcd(b,a%b,y,x); y-=(a/b)*x; } else { x=1; y=0; } return d; } i64 inverse(i64 a){ i64 x,y; extgcd(a,p,x,y); return (x%p+p)%p; } }; template ostream &operator<<(ostream& os, const Fp

&x) { os << x.x; return os; } template i64 abs(const Fp

& x){ return x.x; } template class matrix{ public: int m,n; vector> a; matrix(){ m=n=2; a=vector>(2,vector(2)); a[0][0]=a[1][1]=1; } matrix(int m_,int n_):m(m_),n(n_),a(m_,vector(n_)){} matrix(const vector> &v):m(v.size()),n((v.size()==0 or v[0].size()==0)?0:v[0].size()),a(v){} //matrix(const matrix& other)=default; //~matrix()=default; vector& operator[](int i){ assert(0<=i); assert(i operator+()const{ return *this; } matrix operator-()const{ return K(-1)**this; } K at(int i,int j)const{ return a[i][j]; } matrix& operator=(const matrix &other)=default; matrix& operator+=(const matrix &other){ assert(m==other.m); assert(n==other.n); for(int i=0; i& operator-=(const matrix &other){ return (*this)+=-other; } matrix& operator*=(const matrix &other){ assert(n==other.m); vector> b(m,vector(other.n)); for(int i=0; i& operator/=(const K& k){ assert(k!=K(0)); for(int i=0; i& operator%=(const K& k){ assert(k!=K(0)); for(int i=0; k operator+(const matrix& other)const{ return matrix(*this)+=other; } matrix operator-(const matrix& other)const{ return matrix(*this)-=other; } matrix operator*(const matrix& other)const{ return matrix(*this)*=other; } matrix operator/(const K& k)const{ return matrix(*this)/=k; } matrix operator%(const K& k)const{ return matrix(*this)%=k; } bool operator==(const matrix &other)const{ if(m!=other.m or n!=other.n) return false; for(int i=0; i &other)const{ return !((*this)==other); } static matrix E(int m){ assert(0<=m); matrix E_(m,m); for(int i=0; i e(int m,int i){ assert(0<=i); assert(i e_; e_[i][0]=K(1); return e_; } }; template matrix operator*(const K& k,const matrix &x){ matrix res(x); for(int i=0; i K tr(const matrix& x){ assert(x.m==x.n); K res(0); for(int i=0; i>; mat mul(mat a,mat b){ mat res(2,2); rep(i,0,2) rep(j,0,2) rep(k,0,2) res[i][j]+=a[i][k]*b[k][j]; return res; } void solve(){ int n; cin >> n; vector> tree(n); vector> edges; rep(i,0,n-1){ int a,b; cin >> a >> b; tree[a].push_back(b); tree[b].push_back(a); edges.push_back(make_pair(a,b)); } vector par(n),dep(n); function dfs=[&](int u,int p,int d){ par[u]=p; dep[u]=d; for(int v:tree[u]){ if(v==p) continue; dfs(v,u,d+1); } }; dfs(0,-1,0); rep(i,0,n-1) if(dep[edges[i].first]>dep[edges[i].second]) swap(dep[edges[i].first],dep[edges[i].second]); using seg_mat=segtree; HeavyLightDecomposer> hld(tree,0); vector connections(n,mat::E(2)); rep(i,0,hld.segments.size()){ hld.segments[i].init(hld.paths[i].size()-1, mat::E(2), mat::E(2)); } int q; cin >> q; rep(i,0,q){ char t; cin >> t; if(t=='x'){ int i; i64 x00,x01,x10,x11; cin >> i >> x00 >> x01 >> x10 >> x11; int a=edges[i].first,b=edges[i].second; mat tmp(2,2); tmp[0][0]=x00; tmp[0][1]=x01; tmp[1][0]=x10; tmp[1][1]=x11; if(hld.path_id[a]==hld.path_id[b]){ assert(hld.local_index[b]-1>=0); print(hld.local_index[b]-1); hld.segments[hld.path_id[b]].update(hld.local_index[a],tmp); }else{ connections[b]=tmp; } }else{ int i,j; cin >> i >> j; mat ans; while(true){ int pathj=hld.path_id[j]; if(hld.path_id[i]==hld.path_id[j]){ int l=hld.local_index[i],r=hld.local_index[j]; print(l); print(r); ans=hld.segments[pathj].query(l,r)*ans; break; } ans=hld.segments[pathj].query(0,hld.local_index[j])*ans; ans=connections[hld.first[j]]*ans; j=hld.go_up(j); } cout << ans[0][0] << " " << ans[0][1] << " " << ans[1][0] << " " << ans[1][1] << endl; } } } int main(){ std::cin.tie(0); std::ios::sync_with_stdio(false); cout.setf(ios::fixed); cout.precision(16); solve(); return 0; }