import std.conv, std.stdio, std.string; import std.algorithm, std.array, std.bigint, std.container, std.math, std.range, std.regex, std.typecons; import core.bitop; class EOFException : Throwable { this() { super("EOF"); } } string[] tokens; string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; } int readInt() { return readToken().to!int; } long readLong() { return readToken().to!long; } real readReal() { return readToken().to!real; } void chmin(T)(ref T t, in T f) { if (t > f) t = f; } void chmax(T)(ref T t, in T f) { if (t < f) t = f; } int binarySearch(T)(in T[] as, in bool delegate(T) test) { int low = -1, upp = cast(int)(as.length); for (; low + 1 < upp; ) { int mid = (low + upp) >> 1; (test(as[mid]) ? low : upp) = mid; } return upp; } int lowerBound(T)(in T[] as, in T val) { return as.binarySearch((T a) => (a < val)); } int upperBound(T)(in T[] as, in T val) { return as.binarySearch((T a) => (a <= val)); } immutable MO = 10L^^9 + 7; immutable LIM_LOGN = 20; class SegmentTree { int n; long[] coefSum; long[] sum, add; this(int n_, long[] ini, long[] coef) { for (n = 1; n < n_; n <<= 1) {} coefSum = new long[n + 1]; foreach (i; 0 .. n_) { coefSum[i + 1] = (coefSum[i] + coef[i]) % MO; } coefSum[n_ + 1 .. $] = coefSum[n_]; sum = new long[n << 1]; add = new long[n << 1]; foreach (i; 0 .. n_) { sum[n + i] = ini[i]; } foreach_reverse (u; 1 .. n) { sum[u] = (sum[u << 1] + sum[u << 1 | 1]) % MO; } } long query(int u, int l, int r, int a, int b, long val) { chmax(a, l); chmin(b, r); if (a >= b) { return 0; } debug{ // writefln("query %s [%s, %s); [%s, %s) %s",u,l,r,a,b,val); } if (a == l && b == r) { (sum[u] += (coefSum[r] - coefSum[l]) * val) %= MO; (add[u] += val) %= MO; return sum[u]; } const uL = u << 1; const uR = u << 1 | 1; const mid = (l + r) >> 1; (sum[uL] += (coefSum[mid] - coefSum[l]) * add[u]) %= MO; (add[uL] += add[u]) %= MO; (sum[uR] += (coefSum[r] - coefSum[mid]) * add[u]) %= MO; (add[uR] += add[u]) %= MO; add[u] = 0; const ret = (query(uL, l, mid, a, b, val) + query(uR, mid, r, a, b, val)) % MO; sum[u] = (sum[uL] + sum[uR]) % MO; return ret; } long query(int a, int b, long val) { return query(1, 0, n, a, b + 1, val); } } int N; long[] S; long[] C; int[] A, B; int Q; int[] T, X, Y; long[] Z; int[][] graph; int[][] par; int[] dep; int[] sz; int E; int[] F; int[][] us; int[] es, fs; void dfs(int u, int p, int d) { par[0][u] = p; dep[u] = d; sz[u] = 1; foreach (v; graph[u]) { if (v != p) { dfs(v, u, d + 1); sz[u] += sz[v]; } } bool found; foreach (v; graph[u]) { if (v != p) { if (2 * sz[v] >= sz[u]) { debug { writefln("heavy %s %s", u, v); } found = true; es[u] = es[v]; } } } if (!found) { es[u] = E++; F ~= 0; } fs[u] = F[es[u]]++; } int getLCA(int u, int v) { foreach_reverse (j; 0 .. LIM_LOGN) { if (dep[u] - (1 << j) >= dep[v]) { u = par[j][u]; } if (dep[v] - (1 << j) >= dep[u]) { v = par[j][v]; } } foreach_reverse (j; 0 .. LIM_LOGN) { if (par[j][u] != par[j][v]) { u = par[j][u]; v = par[j][v]; } } if (u != v) { u = par[0][u]; } return u; } void main() { try { for (; ; ) { N = readInt(); S = new long[N]; foreach (u; 0 .. N) { S[u] = readLong(); } C = new long[N]; foreach (u; 0 .. N) { C[u] = readLong(); } A = new int[N - 1]; B = new int[N - 1]; foreach (i; 0 .. N - 1) { A[i] = readInt() - 1; B[i] = readInt() - 1; } Q = readInt(); T = new int[Q]; X = new int[Q]; Y = new int[Q]; Z = new long[Q]; foreach (q; 0 .. Q) { T[q] = readInt(); X[q] = readInt() - 1; Y[q] = readInt() - 1; if (T[q] == 0) { Z[q] = readLong(); } } graph = new int[][N]; foreach (i; 0 .. N - 1) { graph[A[i]] ~= B[i]; graph[B[i]] ~= A[i]; } par = new int[][](LIM_LOGN, N); dep = new int[N]; sz = new int[N]; E = 0; F = []; es = new int[N]; fs = new int[N]; dfs(0, 0, 0); foreach (j; 1 .. LIM_LOGN) { foreach (u; 0 .. N) { par[j][u] = par[j - 1][par[j - 1][u]]; } } us = new int[][E]; foreach (e; 0 .. E) { us[e] = new int[F[e]]; } foreach (u; 0 .. N) { fs[u] = F[es[u]] - 1 - fs[u]; us[es[u]][fs[u]] = u; } debug { writefln("E = %s", E); writefln("F = %s", F); writefln("es = %s", es); writefln("fs = %s", fs); writefln("us = %s", us); } auto segs = new SegmentTree[E]; foreach (e; 0 .. E) { segs[e] = new SegmentTree(F[e], us[e].map!(u => S[u]).array, us[e].map!(u => C[u]).array); } long solve(int u, long val) { long ret; for (; ; ) { debug{ // writeln(" ",es[u]," ",fs[u]," ",val); } (ret += segs[es[u]].query(0, fs[u], val)) %= MO; u = us[es[u]][0]; if (u == 0) { break; } u = par[0][u]; } return ret; } foreach (q; 0 .. Q) { const l = getLCA(X[q], Y[q]); debug { writefln("X[q] = %s, Y[q] = %s: l = %s", X[q], Y[q], l); } long ans = (solve(X[q], +Z[q]) + solve(Y[q], +Z[q]) - solve(l, -Z[q])) % MO; ans = (ans % MO + MO) % MO; if (T[q] == 1) { writeln(ans); } } } } catch (EOFException e) { } }