#define PROBLEM \
"https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_5_E"
#include<bits/stdc++.h>#define REP(i, n) for (int i = 0; i < (n); i++)
#include"library/algebra/lazy/AddSum.hpp"
#include"library/tree/Tree.hpp"
#include"library/tree/TreeLazy.hpp"usingll=longlong;intmain(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);intn;std::cin>>n;Treet(n);REP(i,n){intk;std::cin>>k;REP(_,k){intc;std::cin>>c;t.add_edge(i,c);}}t.build(0);TreeLazy<Tree,LazyAddSum<ll>>TL(t,cnt_init(n,0LL));// 辺の情報は子に持たせる// 各頂点 v について、根から 1 移動した点が必要// Tree に jump を実装してないので無理くり求めるstd::vector<int>root2(n,-1);for(intv:t.BFS){if(v==0)continue;intp=t.parent(v).to;if(p==0)root2[v]=v;elseroot2[v]=root2[p];}intq;std::cin>>q;REP(_,q){intc;std::cin>>c;if(c){intu;std::cin>>u;std::cout<<TL.path_prod(u,root2[u]).first<<"\n";}else{intv,w;std::cin>>v>>w;TL.path_apply(v,root2[v],w);}}}
#line 1 "test/AOJ/GRL_5_E.test.cpp"
#define PROBLEM \
"https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_5_E"
#include<bits/stdc++.h>#define REP(i, n) for (int i = 0; i < (n); i++)
#line 2 "library/algebra/group/Add.hpp"
template<typenameX>structGroupAdd{usingvalue_type=X;staticconstexprXop(constX&x,constX&y)noexcept{returnx+y;}staticconstexprvoidRchop(X&x,constX&y){x+=y;}staticconstexprvoidLchop(constX&x,X&y){y+=x;}staticconstexprXinverse(constX&x)noexcept{return-x;}staticconstexprXpower(constX&x,longlongn)noexcept{returnX(n)*x;}staticconstexprXunit(){returnX(0);}staticconstexprboolcommute=true;};#line 1 "library/algebra/group/CntSum.hpp"
template<typenameX>structGroupCntSum{usingP=std::pair<X,X>;usingvalue_type=P;staticconstexprPop(constP&x,constP&y){return{x.first+y.first,x.second+y.second};}staticconstexprvoidRchop(P&x,constP&y){x.first+=y.first;x.second+=y.second;}staticconstexprvoidLchop(constP&x,P&y){y.first+=x.first;y.second+=x.second;}staticconstexprPinverse(constP&x){return{-x.fi,-x.se};}staticconstexprPunit(){return{0,0};}staticconstexprboolcommute=true;};template<typenameX>std::vector<std::pair<X,X>>cnt_init(intn,constX&x){returnstd::vector<std::pair<X,X>>(n,{x,1});}template<typenameX>std::vector<std::pair<X,X>>cnt_init(conststd::vector<X>&v){intn=v.size();std::vector<std::pair<X,X>>res(n);for(inti=0;i<n;i++)res[i]={v[i],1};returnres;}#line 4 "library/algebra/lazy/AddSum.hpp"
template<typenameX>structLazyAddSum{usingMX=GroupCntSum<X>;usingMF=GroupAdd<X>;usingS=typenameMX::value_type;staticconstexprSmapping(constX&f,constS&x){return{x.first+f*x.second,x.second};}};#line 2 "library/graph/Graph.hpp"
#line 6 "library/graph/Graph.hpp"
structEdge{intfrom,to;Edge()=default;Edge(intfrom,intto):from(from),to(to){}operatorint()const{returnto;}};structGraph{intn;usingedge_type=Edge;std::vector<edge_type>edges;protected:std::vector<int>in_deg;boolprepared;classOutgoingEdges{Graph*g;intl,r;public:OutgoingEdges(Graph*g,intl,intr):g(g),l(l),r(r){}edge_type*begin(){return&(g->edges[l]);}edge_type*end(){return&(g->edges[r]);}edge_type&operator[](inti){returng->edges[l+i];}intsize()const{returnr-l;}};classConstOutgoingEdges{constGraph*g;intl,r;public:ConstOutgoingEdges(constGraph*g,intl,intr):g(g),l(l),r(r){}constedge_type*begin()const{return&(g->edges[l]);}constedge_type*end()const{return&(g->edges[r]);}constedge_type&operator[](inti)const{returng->edges[l+i];}intsize()const{returnr-l;}};public:OutgoingEdgesoperator[](intv){assert(prepared);return{this,in_deg[v],in_deg[v+1]};}constConstOutgoingEdgesoperator[](intv)const{assert(prepared);return{this,in_deg[v],in_deg[v+1]};}boolis_prepared()const{returnprepared;}Graph():n(0),in_deg(1,0),prepared(false){}Graph(intn):n(n),in_deg(n+1,0),prepared(false){}Graph(intn,intm,booldirected=false,intindexed=1):n(n),in_deg(n+1,0),prepared(false){scan(m,directed,indexed);}voidresize(intn){n=n;}voidadd_arc(intfrom,intto){assert(!prepared);assert(0<=fromandfrom<nand0<=toandto<n);edges.emplace_back(from,to);in_deg[from+1]++;}voidadd_edge(intu,intv){add_arc(u,v);add_arc(v,u);}voidadd_arc(constedge_type&e){add_arc(e.from,e.to);}voidadd_edge(constedge_type&e){add_edge(e.from,e.to);}voidscan(intm,booldirected=false,intindexed=1){edges.reserve(directed?m:2*m);while(m--){intu,v;std::cin>>u>>v;u-=indexed;v-=indexed;if(directed)add_arc(u,v);elseadd_edge(u,v);}build();}voidbuild(){assert(!prepared);prepared=true;for(intv=0;v<n;v++)in_deg[v+1]+=in_deg[v];std::vector<edge_type>new_edges(in_deg.back());autocounter=in_deg;for(auto&&e:edges)new_edges[counter[e.from]++]=e;edges=new_edges;}voidgraph_debug()const{#ifndef __LOCAL
return;#endif
assert(prepared);for(intfrom=0;from<n;from++){std::cerr<<from<<";";for(inti=in_deg[from];i<in_deg[from+1];i++)std::cerr<<edges[i].to<<" ";std::cerr<<"\n";}}};#line 3 "library/tree/Tree.hpp"
structTree:Graph{usingGraph::Graph;Tree()=default;introot=-1;std::vector<int>DFS,BFS,depth;voidscan_root(intindexed=1){for(inti=1;i<n;i++){intp;std::cin>>p;add_edge(p-indexed,i);}build();}voidscan(intindexed=1){Graph::scan(n-1,false,indexed);build();}edge_type&parent(intv){assert(~rootandroot!=v);return(*this)[v][0];}constedge_type&parent(intv)const{assert(~rootandroot!=v);return(*this)[v][0];}OutgoingEdgesson(intv){assert(~root);if(v==root)return{this,in_deg[v],in_deg[v+1]};return{this,in_deg[v]+1,in_deg[v+1]};}private:voiddfs(intv,intpre=-1){for(auto&e:(*this)[v]){if(e.to==pre)std::swap((*this)[v][0],e);else{depth[e.to]=depth[v]+1;dfs(e.to,v);}}DFS.push_back(v);}public:voidbuild(intr=0){if(!is_prepared())Graph::build();if(~root){assert(r==root);return;}root=r;depth=std::vector<int>(n,0);DFS.reserve(n);BFS.reserve(n);dfs(root);std::queue<int>que;que.push(root);while(que.size()){intp=que.front();que.pop();BFS.push_back(p);for(constauto&e:son(p))que.push(e.to);}}};#line 2 "library/algebra/Reverse.hpp"
template<typenameAlgebra>structAlgebraReverse:Algebra{usingX=typenameAlgebra::value_type;staticconstexprXop(constX&x,constX&y){returnAlgebra::op(y,x);}staticconstexprvoidRchop(X&x,constX&y){Algebra::Lchop(y,x);}staticconstexprvoidLchop(constX&x,X&y){Algebra::Rchop(y,x);}};#line 3 "library/algebra/lazy/Reverse.hpp"
template<typenameLazy>structLazyReverse:Lazy{usingMX=AlgebraReverse<typenameLazy::MX>;};#line 2 "library/segtree/LazySegmentTree.hpp"
template<typenameLazy>classLazySegmentTree{usingMX=typenameLazy::MX;usingMF=typenameLazy::MF;usingX=typenameMX::value_type;usingF=typenameMF::value_type;intn,log,size;std::vector<X>dat;std::vector<F>laz;Xreflect(intk){if(k<size)returnLazy::mapping(laz[k],dat[k]);returndat[k];}voidpoint_apply(intk,constF&f){if(k<size)MF::Lchop(f,laz[k]);elsedat[k]=Lazy::mapping(f,dat[k]);}voidpush(intk){dat[k]=reflect(k);point_apply(2*k,laz[k]);point_apply(2*k+1,laz[k]);laz[k]=MF::unit();}voidthrust(intk){for(inti=log;i;i--)push(k>>i);}voidupdate(inti){dat[i]=MX::op(reflect(2*i),reflect(2*i+1));}voidrecalc(intk){while(k>>=1)update(k);}public:LazySegmentTree():LazySegmentTree(0){}LazySegmentTree(intn):LazySegmentTree(std::vector<X>(n,MX::unit())){}LazySegmentTree(conststd::vector<X>&v):n(v.size()){for(log=1;(1<<log)<n;log++){}size=1<<log;dat.assign(size<<1,MX::unit());laz.assign(size,MF::unit());for(inti=0;i<n;++i)dat[size+i]=v[i];for(inti=size-1;i>=1;--i)update(i);}voidset(intp,Xx){assert(0<=pandp<n);thrust(p+=size);dat[p]=x;recalc(p);}Xoperator[](intp){assert(0<=pandp<n);thrust(p+=size);returnreflect(p);}Xprod(intL,intR){assert(0<=LandL<=RandR<=n);if(L==R)returnMX::unit();thrust(L+=size);thrust((R+=size-1)++);Xvl=MX::unit(),vr=MX::unit();while(L<R){if(L&1)MX::Rchop(vl,reflect(L++));if(R&1)MX::Lchop(reflect(--R),vr);L>>=1,R>>=1;}returnMX::op(vl,vr);}voidapply(intl,intr,Ff){assert(0<=l&&l<=r&&r<=n);if(l==r)return;thrust(l+=size);thrust(r+=size-1);for(intL=l,R=r+1;L<R;L>>=1,R>>=1){if(L&1)point_apply(L++,f);if(R&1)point_apply(--R,f);}recalc(l);recalc(r);}};#line 2 "library/tree/HLD.hpp"
template<typenameTREE>structHLD{intn;TREET;std::vector<int>sz,head,id,id2,rev_id;boolprepared;HLD(TREET_):T(T_),n(T_.n),sz(n),head(n),id(n),id2(n),rev_id(n),prepared(false){}HLD()=default;private:voiddfs_sz(intv){sz[v]=1;for(auto&e:T.son(v)){dfs_sz(e.to);sz[v]+=sz[e.to];if(sz[e.to]>sz[T.son(v)[0].to])std::swap(e,T.son(v)[0]);}}voiddfs_hld(intv,int&k){id[v]=k++;rev_id[id[v]]=v;for(inti=0;i<T.son(v).size();i++){intto=T.son(v)[i];head[to]=(i?to:head[v]);dfs_hld(to,k);}id2[v]=k;}public:std::vector<int>build(intr=0){assert(!prepared);prepared=true;if(~T.root)assert(T.root==r);elseT.build(r);head[r]=r;dfs_sz(r);intk=0;dfs_hld(r,k);returnid;}intlca(intu,intv)const{assert(prepared);while(head[u]!=head[v])if(T.depth[head[u]]>T.depth[head[v]])u=T.parent(head[u]);elsev=T.parent(head[v]);return(T.depth[u]<T.depth[v]?u:v);}intdistance(intu,intv)const{intw=lca(u,v);returnT.depth[u]+T.depth[v]-T.depth[w]*2;}// v の k 個上の頂点を返すintkth_parent(intv,intk)const{assert(prepared);if(T.depth[v]<k)return-1;while(T.depth[v]-T.depth[head[v]]<k){k-=T.depth[v]-T.depth[head[v]]+1;v=T.parent(head[v]);}returnrev_id[id[v]-k];}// u から v へ k 回移動した頂点を返すintjump(intu,intv,intk)const{assert(prepared);intw=lca(u,v);if(T.depth[u]+T.depth[v]-T.depth[w]*2<k)return-1;if(T.depth[u]-T.depth[w]>=k)returnkth_parent(u,k);returnkth_parent(v,T.depth[u]+T.depth[v]-T.depth[w]*2-k);}// l=lca(u,v) とした時、[u,l] パスと [v,l] パス を閉区間の組みで返すusingpath_t=std::vector<std::pair<int,int>>;std::pair<path_t,path_t>path(intu,intv)const{assert(prepared);path_tpath_u,path_v;while(u!=v){if(head[u]==head[v]){if(T.depth[u]<T.depth[v])path_v.emplace_back(id[v],id[u]);elsepath_u.emplace_back(id[u],id[v]);break;}if(T.depth[head[u]]<T.depth[head[v]]){path_v.emplace_back(id[v],id[head[v]]);v=T.parent(head[v]);}else{path_u.emplace_back(id[u],id[head[u]]);u=T.parent(head[u]);}}if(u==v)path_u.emplace_back(id[u],id[u]);return{path_u,path_v};}// [l,r) が v の部分木std::pair<int,int>subtree(intv)const{assert(prepared);return{id[v],id2[v]};}};#line 5 "library/tree/TreeLazy.hpp"
template<typenameTREE,typenameLazy>structTreeLazy{usingMX=typenameLazy::MX;usingMF=typenameLazy::MF;usingX=typenameMX::value_type;usingF=typenameMF::value_type;usingLazy_r=LazyReverse<Lazy>;intn;TREET;HLD<Tree>hld;std::vector<int>hld_id,euler_in,euler_out;LazySegmentTree<Lazy>seg;LazySegmentTree<Lazy_r>seg_r;TreeLazy(constTREE&T_,intr=0):T(T_),hld(T_),n(T_.n),seg(n),seg_r(n){T.build(r);hld_id=hld.build(r);}TreeLazy(constTREE&T_,std::vector<X>a,intr=0):T(T_),hld(T_),n(T_.n){T.build(r);hld_id=hld.build(r);std::vector<X>hld_a(n);for(intv=0;v<n;v++)hld_a[hld_id[v]]=a[v];seg=LazySegmentTree<Lazy>(hld_a);if(!MX::commute)seg_r=LazySegmentTree<Lazy_r>(hld_a);}voidset(intv,Xx){seg.set(hld_id[v],x);if(!MX::commute)seg_r.set(hld_id[v],x);}voidmultiply(intv,Xx){seg.multiply(hld_id[v],x);if(!MX::commute)seg_r.multiply(hld_id[v],x);}Xget(intv){returnseg.get(hld_id[v]);}// [u,v]パスの monoid 積Xpath_prod(intu,intv){auto[path_u,path_v]=hld.path(u,v);Xprod_u=MX::unit(),prod_v=MX::unit();for(constauto&[l,r]:path_u){Xval=(MX::commute?seg.prod(r,l+1):seg_r.prod(r,l+1));MX::Rchop(prod_u,val);}for(constauto&[l,r]:path_v){Xval=seg.prod(r,l+1);MX::Lchop(val,prod_v);}returnMX::op(prod_u,prod_v);}// root -> pathXpath_root_prod(intv){returnpath_prod(T.root,v);}voidpath_apply(intu,intv,constF&f){auto[path_u,path_v]=hld.path(u,v);for(constauto&[l,r]:path_u){seg.apply(r,l+1,f);if(!MX::commute)seg_r.apply(r,l+1,f);}for(constauto&[l,r]:path_v){seg.apply(r,l+1,f);if(!MX::commute)seg_r.apply(r,l+1,f);}}voidpath_root_apply(intv,constF&f){path_apply(T.root,v,f);}Xsubtree_prod(intv){assert(MX::commute);auto[l,r]=hld.subtree(v);returnseg.prod(l,r);}voidsubtree_apply(intv,constF&f){auto[l,r]=hld.subtree(v);seg.apply(l,r,f);if(!MX::commute)seg_r.apply(l,r,f);}};#line 10 "test/AOJ/GRL_5_E.test.cpp"
usingll=longlong;intmain(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);intn;std::cin>>n;Treet(n);REP(i,n){intk;std::cin>>k;REP(_,k){intc;std::cin>>c;t.add_edge(i,c);}}t.build(0);TreeLazy<Tree,LazyAddSum<ll>>TL(t,cnt_init(n,0LL));// 辺の情報は子に持たせる// 各頂点 v について、根から 1 移動した点が必要// Tree に jump を実装してないので無理くり求めるstd::vector<int>root2(n,-1);for(intv:t.BFS){if(v==0)continue;intp=t.parent(v).to;if(p==0)root2[v]=v;elseroot2[v]=root2[p];}intq;std::cin>>q;REP(_,q){intc;std::cin>>c;if(c){intu;std::cin>>u;std::cout<<TL.path_prod(u,root2[u]).first<<"\n";}else{intv,w;std::cin>>v>>w;TL.path_apply(v,root2[v],w);}}}