#include "bits/stdc++.h" using namespace std; #define FOR(i,j,k) for(int (i)=(j);(i)<(int)(k);++(i)) #define rep(i,j) FOR(i,0,j) #define each(x,y) for(auto &(x):(y)) #define mp make_pair #define all(x) (x).begin(),(x).end() #define debug(x) cout<<#x<<": "<<(x)< pii; typedef vector vi; typedef vector vll; class LCA{ public: LCA(){ } LCA(const vector> &G, int root = 0):V((int)G.size()), depth(V), parent(V){ rep(i, LG)ancestor[i] = vector(V); dfs(root, 0, 0, G); rep(i, V) ancestor[0][i] = parent[i]; rep(i,LG-1)rep(v,V) ancestor[i + 1][v] = ancestor[i][ancestor[i][v]]; } int get(int u, int v){ if(depth[u] < depth[v]) swap(u, v); int dist = depth[u] - depth[v]; for(int i = 0; i < LG; ++i) if((dist >> i) & 1) u = ancestor[i][u]; if(u == v) return u; for(int i = LG - 1; i >= 0; --i){ if(ancestor[i][u] != ancestor[i][v]){ u = ancestor[i][u]; v = ancestor[i][v]; } } return ancestor[0][u]; } int getDepth(int u){ return depth[u]; } int goUp(int u, int len){ for(int i = 0; i < LG; ++i) if(len >> i & 1)u = ancestor[i][u]; return u; } int distance(int u, int v){ return depth[u] + depth[v] - 2 * depth[get(u, v)]; } int getParent(int u){ return parent[u]; } static const int LG = 18; private: int V; vector depth, parent, ancestor[LG]; void dfs(int v, int p, int d, const vector> &G){ depth[v] = d; parent[v] = p; for(int to : G[v]){ if(to != p){ dfs(to, v, d + 1, G); } } } }; struct HLDecomposition{ vector subtreeSize, parent, group, idInPath; vector> paths; HLDecomposition(){ } HLDecomposition(const vector> &G){ subtreeSize = parent = group = idInPath = vector(G.size(), 1); dfs1(G, 0, -1); paths.push_back(vector()); dfs2(G, 0, -1, 0); } int dfs1(const vector> &G, int u, int pre){ parent[u] = pre; int &res = subtreeSize[u]; for(int v : G[u]){ if(v != pre){ res += dfs1(G, v, u); } } return res; } void dfs2(const vector> &G, int u, int pre, int pathId){ idInPath[u] = (int)paths[pathId].size(); paths[pathId].push_back(u); group[u] = pathId; int heavy = -1, maxSize = 0; for(int v : G[u]){ if(v != pre && subtreeSize[v] > maxSize){ heavy = v; maxSize = subtreeSize[v]; } } if(heavy != -1){ dfs2(G, heavy, u, pathId); } for(int v : G[u]){ if(v != pre && v != heavy){ paths.push_back(vector()); dfs2(G, v, u, (int)paths.size() - 1); } } } /* 頂点uから根まで登って、その途上にあるパスのIDとそのパスの通過箇所の右端を求める。 */ vector > goToRoot(int u){ vector > res; while(u != -1){ res.emplace_back(group[u], idInPath[u] + 1); u = parent[paths[group[u]][0]]; } return res; } }; template class ModInt{ public: ModInt():value(0){} ModInt(long long val):value((int)(val<0?MOD+val%MOD:val%MOD)){ } ModInt& operator+=(ModInt that){ value = value+that.value; if(value>=MOD)value-=MOD; return *this; } ModInt& operator-=(ModInt that){ value -= that.value; if(value<0)value+=MOD; return *this; } ModInt& operator*=(ModInt that){ value = (int)((long long)value * that.value % MOD); return *this; } ModInt &operator/=(ModInt that){ return *this *= that.inverse(); } ModInt operator+(ModInt that) const{ return ModInt(*this)+=that; } ModInt operator-(ModInt that) const{ return ModInt(*this)-=that; } ModInt operator*(ModInt that) const{ return ModInt(*this)*=that; } ModInt operator/(ModInt that) const { return ModInt(*this) /= that; } ModInt operator^(long long k) const{ if(value == 0)return 0; ModInt n = *this, res = 1; while(k){ if(k & 1)res *= n; n *= n; k >>= 1; } return res; } ModInt inverse() const { long long a = value, b = MOD, u = 1, v = 0; while(b) { long long t = a / b; a -= t * b; swap(a, b); u -= t * v; swap(u, v); } return ModInt(u); } int toi() const{ return value; } private: int value; }; typedef ModInt<1000000007> mint; ostream& operator<<(ostream& os, const mint& x){ os << x.toi(); return os; } // sumC[i][j] // i番目のpathの[0, j)までの和 vector> sumC; int currentSegTree = 0; bool init = true; struct LazySegTreeSum{ int dataSize; vector value, lazy; LazySegTreeSum(int n){ dataSize = 1; while(dataSize < n)dataSize *= 2; int treeSize = 2 * dataSize; value = lazy = vector(treeSize); } void propagate(int index, int curL, int curR){ vector &curSumC = sumC[currentSegTree]; // 自分の値をlazyにもとづいて書き換えて自分のlazyをクリア。 if(lazy[index].toi()){ int left = index * 2, right = index * 2 + 1; if(!init){ value[index] += lazy[index] * (curSumC[curR] - curSumC[curL]); } else{ value[index] += lazy[index] * (curR - curL); } // 子のlazyを書き換える。 if(curR - curL > 1){ lazy[left] += lazy[index]; lazy[right] += lazy[index]; } lazy[index] = 0; } } // [curL, curR) を評価する void update(int index, int curL, int curR, int givenL, int givenR, mint x){ // 範囲外であろうとpropagateは必ず呼ぶ。そうでないと、親がうまく評価されない propagate(index, curL, curR); // 範囲外 if(curR <= givenL || givenR <= curL)return; if(givenL <= curL && curR <= givenR){ // 直接書き換えないでindexのlazyを書き換えてpropagateを呼ぶ lazy[index] += x; propagate(index, curL, curR); } else{ int mid = (curL + curR) / 2; update(index * 2, curL, mid, givenL, givenR, x); update(index * 2 + 1, mid, curR, givenL, givenR, x); value[index] = value[index * 2] + value[index * 2 + 1]; } } void update(int l, int r, mint x){ update(1, 0, dataSize, l, r, x); } mint query(int l, int r){ return query(1, 0, dataSize, l, r); } mint query(int index, int curL, int curR, int givenL, int givenR){ propagate(index, curL, curR); // 範囲外 if(curR <= givenL || givenR <= curL)return 0; if(givenL <= curL && curR <= givenR){ return value[index]; } else{ int mid = (curL + curR) / 2; mint resL = query(index * 2, curL, mid, givenL, givenR); mint resR = query(index * 2 + 1, mid, curR, givenL, givenR); return resL + resR; } } }; int main(){ int N; cin >> N; vector G(N); vector segtree; HLDecomposition hld; LCA lca; // 前処理 { vi S(N), C(N); rep(i, N)scanf("%d", &S[i]); rep(i, N)scanf("%d", &C[i]); rep(i, N - 1){ int A, B; scanf("%d%d", &A, &B); --A; --B; G[A].push_back(B); G[B].push_back(A); } hld = HLDecomposition(G); lca = LCA(G); each(path, hld.paths){ segtree.push_back(LazySegTreeSum(sz(path))); sumC.push_back(vector(sz(path) + 1)); // とりあえず初期値のSを入れておく rep(i, sz(path)){ segtree.back().update(i, i + 1, S[path[i]]); sumC.back()[i + 1] = sumC.back()[i] + C[path[i]]; } vector &curSumC = sumC.back(); for(int i = 0; i <= 30; ++i){ while(sz(curSumC) < (1 << i)){ curSumC.push_back(curSumC.back()); } if(sz(curSumC) == 1 << i)break; } rep(i, 10)curSumC.push_back(curSumC.back()); } init = false; // デバッグ用 { each(tree, segtree){ each(lazy, tree.lazy){ assert(lazy.toi() == 0); } } rep(i, N){ int segId = hld.group[i]; int pos = hld.idInPath[i]; assert(segtree[segId].query(pos, pos + 1).toi() == S[i]); } } } // HL分解のテスト //{ // rep(i, N){ // debug(i + 1); // auto test = hld.goToRoot(i); // each(p, test){ // debug(p.first); // debug(p.second); // } // } //} // クエリ処理 { int Q; cin >> Q; while(Q--){ int q, X, Y; scanf("%d%d%d", &q, &X, &Y); --X; --Y; int l = lca.get(X, Y); if(q == 0){ // パレード int Z; scanf("%d", &Z); for(int u : {X, Y}){ auto segs = hld.goToRoot(u); each(seg, segs){ currentSegTree = seg.first; segtree[currentSegTree].update(0, seg.second, Z); } } auto segs = hld.goToRoot(l); each(seg, segs){ currentSegTree = seg.first; segtree[currentSegTree].update(0, seg.second, -2ll*Z); } segtree[hld.group[l]].update(hld.idInPath[l], hld.idInPath[l] + 1, Z); } else{ mint ans = 0; // めぐるの旅行 for(int u : {X, Y}){ auto segs = hld.goToRoot(u); each(seg, segs){ currentSegTree = seg.first; ans += segtree[currentSegTree].query(0, seg.second); } } auto segs = hld.goToRoot(l); each(seg, segs){ currentSegTree = seg.first; ans -= segtree[currentSegTree].query(0, seg.second) * 2; } ans += segtree[hld.group[l]].query(hld.idInPath[l], hld.idInPath[l] + 1); printf("%d\n", ans.toi()); } } } }