#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int MOD = 1e9 + 7;
const int MAXN = 100005;
const int MAX_VAL = 100005;
// Cấu hình kích thước block tối ưu qua thực nghiệm
const int B_1 = 450; // Kích thước khối theo chỉ số mảng
const int B_2 = 320; // Kích thước khối theo trục giá trị
const int K1 = (MAXN / B_1) + 5;
const int K2 = (MAX_VAL / B_2) + 5;
int n, q;
int a[MAXN];
long long inv[MAX_VAL];
// ===== CẤU TRÚC CHIA CĂN 2 LẦN =====
// Tiết kiệm bộ nhớ bằng cách dùng short cho mảng đếm tích lũy (vì B_1 = 450 < 32767)
short pref_in_vb_cnt[K1][MAX_VAL];
int pref_in_vb_prod[K1][MAX_VAL];
int pref_b_cnt[K1][K2];
int pref_b_prod[K1][K2];
int block_total_prod[K1];
// Hàm tính lũy thừa nhanh
long long power_mod(long long base, long long exp) {
if (exp < 0) return 0;
long long res = 1;
base %= MOD;
while (exp > 0) {
if (exp % 2 == 1) res = res * base % MOD;
base = base * base % MOD;
exp /= 2;
}
return res;
}
// Xây dựng cấu trúc dữ liệu ban đầu
void build_structure() {
int num_blocks = (n + B_1 - 1) / B_1;
int num_val_blocks = (MAX_VAL + B_2 - 1) / B_2;
for (int b = 0; b < num_blocks; ++b) {
block_total_prod[b] = 1;
int start_idx = b * B_1;
int end_idx = min(n - 1, (b + 1) * B_1 - 1);
// Đếm tần suất thô của các phần tử trong khối b
vector<int> local_cnt(MAX_VAL, 0);
for (int i = start_idx; i <= end_idx; ++i) {
local_cnt[a[i]]++;
block_total_prod[b] = 1LL * block_total_prod[b] * a[i] % MOD;
}
// Xây dựng tiền tố tích lũy lồng nhau trên trục giá trị
int current_cnt = 0;
long long current_prod = 1;
for (int vb = 0; vb < num_val_blocks; ++vb) {
int v_start = vb * B_2;
int v_end = min(MAX_VAL - 1, (vb + 1) * B_2 - 1);
int vb_cnt = 0;
long long vb_prod = 1;
for (int v = v_start; v <= v_end; ++v) {
if (local_cnt[v] > 0) {
long long p = power_mod(v, local_cnt[v]);
vb_prod = vb_prod * p % MOD;
vb_cnt += local_cnt[v];
}
pref_in_vb_prod[b][v] = vb_prod;
pref_in_vb_cnt[b][v] = vb_cnt;
}
current_cnt += vb_cnt;
current_prod = current_prod * vb_prod % MOD;
pref_b_cnt[b][vb] = current_cnt;
pref_b_prod[b][vb] = current_prod;
}
}
}
// Thao tác cập nhật điểm online O(B_2 + V/B_2)
void update(int p, int new_v) {
int old_v = a[p];
if (old_v == new_v) return;
int b = p / B_1;
long long old_inv = inv[old_v];
int num_val_blocks = (MAX_VAL + B_2 - 1) / B_2;
// 1. Loại bỏ giá trị cũ khỏi cấu trúc tiền tố giá trị
int old_vb = old_v / B_2;
int end_old_vb = min(MAX_VAL - 1, (old_vb + 1) * B_2 - 1);
for (int v = old_v; v <= end_old_vb; ++v) {
pref_in_vb_cnt[b][v]--;
pref_in_vb_prod[b][v] = 1LL * pref_in_vb_prod[b][v] * old_inv % MOD;
}
for (int vb = old_vb; vb < num_val_blocks; ++vb) {
pref_b_cnt[b][vb]--;
pref_b_prod[b][vb] = 1LL * pref_b_prod[b][vb] * old_inv % MOD;
}
// 2. Thêm giá trị mới vào cấu trúc tiền tố giá trị
int new_vb = new_v / B_2;
int end_new_vb = min(MAX_VAL - 1, (new_vb + 1) * B_2 - 1);
for (int v = new_v; v <= end_new_vb; ++v) {
pref_in_vb_cnt[b][v]++;
pref_in_vb_prod[b][v] = 1LL * pref_in_vb_prod[b][v] * new_v % MOD;
}
for (int vb = new_vb; vb < num_val_blocks; ++vb) {
pref_b_cnt[b][vb]++;
pref_b_prod[b][vb] = 1LL * pref_b_prod[b][vb] * new_v % MOD;
}
// 3. Cập nhật tích tổng của khối và lưu vào mảng gốc
block_total_prod[b] = 1LL * block_total_prod[b] * old_inv % MOD * new_v % MOD;
a[p] = new_v;
}
// Truy vấn tử số S_X = tích các min(a_i, X) trong O(B_1 + N/B_1)
pair<long long, int> query_S(int L, int R, int X) {
if (X <= 0) return {0, 0};
if (X >= MAX_VAL) X = MAX_VAL - 1;
long long ans_prod = 1;
int ans_cnt = 0;
int bl = L / B_1;
int br = R / B_1;
if (bl == br) { // Nằm chung 1 khối chỉ số
for (int i = L; i <= R; ++i) {
if (a[i] <= X) {
ans_prod = ans_prod * a[i] % MOD;
ans_cnt++;
}
}
} else {
// Phần lẻ khối đầu
int end_bl = (bl + 1) * B_1 - 1;
for (int i = L; i <= end_bl; ++i) {
if (a[i] <= X) {
ans_prod = ans_prod * a[i] % MOD;
ans_cnt++;
}
}
// Các khối nguyên ở giữa lấy kết quả O(1)
int X_vb = X / B_2;
for (int b = bl + 1; b < br; ++b) {
if (X_vb > 0) {
ans_prod = ans_prod * pref_b_prod[b][X_vb - 1] % MOD;
ans_cnt += pref_b_cnt[b][X_vb - 1];
}
ans_prod = ans_prod * pref_in_vb_prod[b][X] % MOD;
ans_cnt += pref_in_vb_cnt[b][X];
}
// Phần lẻ khối cuối
int start_br = br * B_1;
for (int i = start_br; i <= R; ++i) {
if (a[i] <= X) {
ans_prod = ans_prod * a[i] % MOD;
ans_cnt++;
}
}
}
return {ans_prod, ans_cnt};
}
// Truy vấn mẫu số D = tích các a_i trong O(B_1 + N/B_1)
long long query_D(int L, int R) {
long long ans = 1;
int bl = L / B_1;
int br = R / B_1;
if (bl == br) {
for (int i = L; i <= R; ++i) ans = ans * a[i] % MOD;
} else {
int end_bl = (bl + 1) * B_1 - 1;
for (int i = L; i <= end_bl; ++i) ans = ans * a[i] % MOD;
for (int b = bl + 1; b < br; ++b) ans = ans * block_total_prod[b] % MOD;
int start_br = br * B_1;
for (int i = start_br; i <= R; ++i) ans = ans * a[i] % MOD;
}
return ans;
}
int main() {
// Tối ưu hóa luồng I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Tính trước nghịch đảo modulo tuyến tính O(MAX_VAL)
inv[1] = 1;
for (int i = 2; i < MAX_VAL; ++i) {
inv[i] = MOD - MOD / i * inv[MOD % i] % MOD;
}
if (!(cin >> n)) return 0;
for (int i = 0; i < n; ++i) cin >> a[i];
build_structure();
cin >> q;
while (q--) {
int type;
cin >> type;
if (type == 1) {
int p, v;
cin >> p >> v;
--p; // Chuyển về 0-indexed
update(p, v);
} else {
int L, R, X;
cin >> L >> R >> X;
--L; --R; // Chuyển về 0-indexed
int window_size = R - L + 1;
// Tính P(max <= X)
auto S_X = query_S(L, R, X);
long long total_S_X = S_X.first * power_mod(X, window_size - S_X.second) % MOD;
// Tính P(max <= X-1)
long long total_S_X_minus_1 = 0;
if (X - 1 > 0) {
auto S_X_1 = query_S(L, R, X - 1);
total_S_X_minus_1 = S_X_1.first * power_mod(X - 1, window_size - S_X_1.second) % MOD;
}
// Kết quả xác suất tích lũy
long long num = (total_S_X - total_S_X_minus_1 + MOD) % MOD;
long long den = query_D(L, R);
long long ans = num * power_mod(den, MOD - 2) % MOD;
cout << ans << "\n";
}
}
return 0;
}