#include using namespace std; #if __has_include() #include using namespace atcoder; templateistream &operator>>(istream &is,static_modint &a){long long b;is>>b;a=b;return is;} istream &operator>>(istream &is,modint &a){long long b;cin>>b;a=b;return is;} #endif using ll=long long; using ull=unsigned long long; using P=pair; templateusing minque=priority_queue,greater>; templatebool chmax(T &a,const T &b){return (abool chmin(T &a,const T &b){return (a>b?(a=b,true):false);} templateistream &operator>>(istream &is,pair&p){is>>p.first>>p.second;return is;} templateistream &operator>>(istream &is,vector &a){for(auto &i:a)is>>i;return is;} templatevoid operator++(pair&a,int n){a.first++,a.second++;} templatevoid operator--(pair&a,int n){a.first--,a.second--;} templatevoid operator++(vector&a,int n){for(auto &i:a)i++;} templatevoid operator--(vector&a,int n){for(auto &i:a)i--;} #define reps(i,a,n) for(int i=(a);i<(n);i++) #define rep(i,n) reps(i,0,n) #define all(x) x.begin(),x.end() #define pcnt(x) __builtin_popcount(x) ll myceil(ll a,ll b){return (a+b-1)/b;} template vector vec(T d,int sz){ return vector(sz,d); } template auto vec(T d,int a,U...b){ return vector(d,b...))>(a,vec(d,b...)); } #ifdef LOCAL #include "debug.h" #else #define debug(...) static_cast(0) templateostream &operator<<(ostream &os,const pair&p){os<>testcase; for(int i=0;i>to; int root; vectorpar,pathtop,in,out; public: vectorstsize; private: void st_dfs(int x,int p){ par[x]=p; stsize[x]=1; for(auto &i:to[x]){ if(i==p){ if(i==to[x].back())break; else swap(i,to[x].back()); } st_dfs(i,x); stsize[x]+=stsize[i]; if(stsize[i]>stsize[to[x][0]]){ swap(i,to[x][0]); } } } void hld_dfs(int x,int p,int &id){ in[x]=id++; for(auto i:to[x])if(i!=p){ pathtop[i]=(i==to[x][0]?pathtop[x]:i); hld_dfs(i,x,id); } out[x]=id; } public: HeavyLightDecomposition(int n,int root=0):n(n),to(n),stsize(n),par(n),in(n),out(n),root(root),pathtop(n){} void add_edge(int u,int v){ to[u].emplace_back(v); to[v].emplace_back(u); } void build(){ st_dfs(0,-1); pathtop[root]=root; int id=0; hld_dfs(0,-1,id); } inline int get(int x)const{return in[x];} int lca(int u,int v)const{ int pu=pathtop[u],pv=pathtop[v]; while(pathtop[u]!=pathtop[v]){ if(in[pu]>in[pv])u=par[pu],pu=pathtop[u]; else v=par[pv],pv=pathtop[v]; } return (in[u]>in[v]?v:u); } void subtree_query(int u ,const function &f){ f(in[u],out[u]); } void path_query(int u,int v,const function&f){ int pu=pathtop[u],pv=pathtop[v]; while(pathtop[u]!=pathtop[v]){ if(in[u]>in[v])f(in[pu],in[u]+1),u=par[pu],pu=pathtop[u]; else f(in[pv],in[v]+1),v=par[pv],pv=pathtop[v]; } if(in[u]>in[v])swap(u,v); f(in[u],in[v]+1); } void noncommutative_path_query(int u,int v,const function&f){ int l=lca(u,v); while(pathtop[u]!=pathtop[l]){ f(in[u]+1,in[pathtop[u]]); u=par[pathtop[u]]; } if(u!=l)f(in[u]+1,in[l]+1); f(in[l],in[l]+1); if(v==l)return; vector>query; while(true){ if(pathtop[l]==pathtop[v]){ query.emplace_back(in[l]+1,in[v]+1); break; } query.emplace_back(in[pathtop[v]],in[v]+1); v=par[pathtop[v]]; } reverse(all(query)); for(auto [i,j]:query)f(i,j); } }; template struct Matrix{ vector>A; Matrix(int h,int w):A(h,vector(w,0)){} Matrix(int n):A(n,vector(n,0)){} size_t height()const{return A.size();} size_t width()const{return A[0].size();} const vector &operator[](int k)const{return (A.at(k));} vector &operator[](int k){return (A.at(k));} Matrix I(size_t n){ Matrix m(n); rep(i,n)m[i][i]=1; return m; } Matrix &operator+=(const Matrix &B){ size_t h=height(),w=width(); assert(h==B.height()); assert(w==B.width()); rep(i,h)rep(j,w)(*this)[i][j]+=B[i][j]; return *this; } Matrix &operator-=(const Matrix &B){ size_t h=height(),w=width(); assert(h==B.height()); assert(w==B.width()); rep(i,h)rep(j,w)(*this)[i][j]-=B[i][j]; return *this; } Matrix &operator*=(const Matrix &B){ size_t h=height(),w=B.width(),p=width(); assert(B.height()==p); vector>C(h,vector(w,0)); rep(i,h)rep(k,p)rep(j,w)C[i][j]=(C[i][j]+(*this)[i][k]*B[k][j]); A.swap(C); return *this; } Matrix &operator^=(ll k){ assert(height()==width()); assert(k>=0); Matrix B=I(height()); while(k){ if(k&1)B*=*this; *this *= *this; k>>=1ll; } A.swap(B.A); return *this; } Matrix operator+(const Matrix &B)const{ return (Matrix(*this)+=B); } Matrix operator-(const Matrix &B)const{ return (Matrix(*this)-=B); } Matrix operator*(const Matrix &B)const{ return (Matrix(*this)*=B); } Matrix operator^(const ll k)const{ return (Matrix(*this)^=k); } T det(){ Matrixb(*this); assert(this->height()==this->width()); T ret=1; rep(i,width()){ int id=-1; reps(j,i,width()){ if(b[j][i]!=0)id=j; } if(id==-1)return 0; if(i!=id){ ret*=-1; swap(b[i],b[id]); } ret*=b[i][i]; T inv=b[i][i].inv(); rep(j,width()){ b[i][j]*=inv; } reps(j,i+1,width()){ T x=b[j][i]; rep(k,width()){ b[j][k]-=b[i][k]*x; } } } return ret; } Matrix inv(){ assert(this->height()==this->width()); int n=this->height(); Matrixb(*this); Matrixret=I(n); rep(i,n){ int id=-1; reps(j,i,n){ if(b[j][i]!=0)id=j; } assert(id!=-1); if(i!=id){ swap(b[i],b[id]); swap(ret[i],ret[id]); } T inv=b[i][i].inv(); rep(j,n){ b[i][j]*=inv; ret[i][j]*=inv; } rep(j,n)if(i!=j){ T x=b[j][i]; rep(k,n){ b[j][k]-=b[i][k]*x; ret[j][k]-=ret[i][k]*x; } } } return ret; } }; using mint=modint1000000007; Matrixop(Matrixa,Matrixb){return a*b;} Matrixop2(Matrixa,Matrixb){return b*a;} Matrixe(){ Matrixret(2); ret[0][0]=ret[1][1]=1; return ret; } void SOLVE(){ int n; cin>>n; HeavyLightDecomposition hld(n*2-1); rep(i,n-1){ int a,b; cin>>a>>b; hld.add_edge(a,i+n); hld.add_edge(i+n,b); } hld.build(); int q; cin>>q; segtree,op,e>seg(n*2-1); segtree,op2,e>segrev(n*2-1); while(q--){ char c; cin>>c; if(c=='x'){ int i,a,b,c,d; cin>>i>>a>>b>>c>>d; int id=hld.get(i+n); Matrixnxt(2); nxt[0][0]=a; nxt[0][1]=b; nxt[1][0]=c; nxt[1][1]=d; seg.set(id,nxt); segrev.set(id,nxt); } else if(c=='g'){ int u,v; cin>>u>>v; Matrixans(2); ans[0][0]=ans[1][1]=1; hld.noncommutative_path_query(u,v,[&](int a,int b){ if(a