#include #define GET_MACRO(a, b, c, NAME, ...) NAME #define rep(...) GET_MACRO(__VA_ARGS__, rep3, rep2)(__VA_ARGS__) #define rep2(i, a) rep3 (i, 0, a) #define rep3(i, a, b) for (int i = (a); i < (b); i++) #define repr(...) GET_MACRO(__VA_ARGS__, repr3, repr2)(__VA_ARGS__) #define repr2(i, a) repr3 (i, 0, a) #define repr3(i, a, b) for (int i = (b) - 1; i >= (a); i--) #define chmin(a, b) ((b) < a && (a = (b), true)) #define chmax(a, b) (a < (b) && (a = (b), true)) using namespace std; typedef long long ll; const ll mod = 1e9 + 7; ll modulo(ll a) { a %= mod; a += mod; a %= mod; return a; } struct HL { vector> g; vector vid, depth, head, parent, size; int u, v, k; HL(int n) : g(n), vid(n), depth(n), head(n), parent(n), size(n, 1), k(0) {} void add(int u, int v) { g[u].push_back(v); g[v].push_back(u); } void build() { dfs(0); dfs2(0); } void dfs(int curr, int prev = -1) { head[curr] = curr; parent[curr] = prev; int heavy = -1; rep (i, g[curr].size()) if (g[curr][i] != prev) { int next = g[curr][i]; depth[next] = depth[curr] + 1; dfs(next, curr); size[curr] += size[next]; if (heavy == -1 || size[g[curr][heavy]] < size[next]) heavy = i; } if (heavy != -1) swap(g[curr][0], g[curr][heavy]); } void dfs2(int curr, int prev = -1) { vid[curr] = k++; rep (i, g[curr].size()) if (g[curr][i] != prev) { int next = g[curr][i]; if (!i) head[next] = head[curr]; dfs2(next, curr); } } void set(int u, int v) { this->u = u; this->v = v; } pair next() { if (depth[u] < depth[v]) swap(u, v); if (depth[head[u]] < depth[head[v]]) swap(u, v); int l = head[u] == head[v] ? vid[v] : vid[head[u]], r = vid[u] + 1; u = head[u] == head[v] ? -1 : parent[head[u]]; return {l, r}; } bool has_next() { return u != -1; } }; struct SegmentTree { vector seg, lazy, weight, wsum; int size; SegmentTree(int n) { size = 1; while (size < n) size *= 2; seg.resize(size * 2); lazy.resize(size * 2); weight.resize(size); } void set(int k, ll v, ll w) { seg[k + size - 1] = v; weight[k] = w; } void build() { wsum.resize(size + 1); rep (i, size) { wsum[i + 1] += wsum[i] + weight[i]; wsum[i + 1] %= mod; } repr (i, size - 1) { seg[i] = seg[i * 2 + 1] + seg[i * 2 + 2]; seg[i] %= mod; } } void push(int k, int l, int r) { if (lazy[k] != 0) { seg[k] += lazy[k] * (wsum[r] - wsum[l]); seg[k] = modulo(seg[k]); if (r - l > 1) { (lazy[k * 2 + 1] += lazy[k]) %= mod; (lazy[k * 2 + 2] += lazy[k]) %= mod; } lazy[k] = 0; } } void update(int a, int b, ll v, int k, int l, int r) { push(k, l, r); if (r <= a || b <= l) return; if (a <= l && r <= b) { lazy[k] = v; push(k, l, r); } else { update(a, b, v, k * 2 + 1, l, (l + r) / 2); update(a, b, v, k * 2 + 2, (l + r) / 2, r); seg[k] = seg[k * 2 + 1] + seg[k * 2 + 2]; seg[k] %= mod; } } void update(int a, int b, ll v) { update(a, b, v, 0, 0, size); } ll query(int a, int b, int k, int l, int r) { push(k, l, r); if (r <= a || b <= l) return 0; if (a <= l && r <= b) return seg[k]; ll res = 0; res += query(a, b, k * 2 + 1, l, (l + r) / 2); res += query(a, b, k * 2 + 2, (l + r) / 2, r); return res % mod; } ll query(int a, int b) { return query(a, b, 0, 0, size); } }; int main() { int N; cin >> N; vector S(N), C(N); rep (i, N) scanf("%d", &S[i]); rep (i, N) scanf("%d", &C[i]); HL hl(N); rep (i, N - 1) { int a, b; cin >> a >> b; a--; b--; hl.add(a, b); } hl.build(); SegmentTree tr(N); rep (i, N) { tr.set(hl.vid[i], S[i], C[i]); } tr.build(); int Q; cin >> Q; while (Q--) { int q; scanf("%d", &q); if (q == 0) { int x, y, z; scanf("%d%d%d", &x, &y, &z); x--; y--; hl.set(x, y); while (hl.has_next()) { auto p = hl.next(); tr.update(p.first, p.second, z); } } else { int x, y; scanf("%d%d", &x, &y); x--; y--; hl.set(x, y); ll ans = 0; while (hl.has_next()) { auto p = hl.next(); ans += tr.query(p.first, p.second); ans %= mod; } printf("%d\n", (int)ans); } } }