#include #include using namespace std; using namespace atcoder; struct Fast { Fast() { std::cin.tie(nullptr); ios::sync_with_stdio(false); cout << setprecision(10); } } fast; #define rep(i, a, b) for (int(i) = (a); (i) < (int)(b); (i)++) using ll = long long; using mint = modint998244353; struct S { int size; mint value; }; struct F { bool is_set; mint value; }; S op(S x, S y) { return {x.size + y.size, x.value + y.value}; } S e() { return {0, 0}; } S mapping(F f, S x) { return {x.size, f.value * x.size + (f.is_set ? 0 : x.value)}; } F id() { return {false, 0}; } F composition(F f, F g) { return f.is_set ? f : F{g.is_set, f.value + g.value}; } using lst = lazy_segtree; int main() { const int P_MAX = 100; vector primes; for (int x = 2; x <= P_MAX; x++) { bool ok = true; for (auto p : primes) ok &= x % p > 0; if (ok) primes.push_back(x); } int c = primes.size(); int n; cin >> n; vector> data(c, vector(n)); rep(i, 0, n) { ll a; cin >> a; rep(j, 0, c) { int v = 0, p = primes[j]; for (; a % p == 0; a /= p) v++; data[j][i] = {1, v}; } } vector seg(c); rep(i, 0, c) seg[i] = lst(data[i]); int q; cin >> q; while (q--) { int t, l, r; ll x; cin >> t >> l >> r >> x; l--; if (t == 1) { rep(i, 0, c) { int v = 0, p = primes[i]; for (; x % p == 0; x /= p) v++; seg[i].apply(l, r, F{true, v}); } } else if (t == 2) { rep(i, 0, c) { int v = 0, p = primes[i]; for (; x % p == 0; x /= p) v++; seg[i].apply(l, r, F{false, v}); } } else { mint ans = 1; rep(i, 0, c) { int p = primes[i]; if (p > x) break; ans *= seg[i].prod(l, r).value + 1; } cout << ans.val() << "\n"; } } }