现在要求的是 ,
答案只与 的值 和 其包含的质数有关, 而题目中涉及到的质数不超过 个 .
于是使用两颗线段树, 一颗记录乘积的信息, 一颗记录相关质数出现的信息,
其中质数出现的信息可以以二进制形式存储到 中 .
- 注意线段树乘法懒标记初值为 .
- 不要写成 .
- 应该为 .
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 1e6 + 5;
const int mod = 998244353;
int N;
int M;
int p_cnt;
int A[maxn];
int pos[maxn];
int from[maxn];
int prime[maxn];
int p_inv[maxn];
bool vis[maxn];
ll State;
int Ksm(int a, int b){ int s=1; while(b){ if(b&1) s=1ll*s*a%mod; a=1ll*a*a%mod; b>>=1; } return s; }
void sieve(){
for(reg int i = 2; i <= 300; i ++){
if(!vis[i]) prime[++ p_cnt] = i, p_inv[p_cnt] = (1ll*i-1)*Ksm(i, mod-2)%mod, from[i] = i, pos[i] = p_cnt;
for(reg int j = 1; j <= p_cnt && prime[j]*i <= 300; j ++){
vis[prime[j]*i] = 1; from[prime[j]*i] = prime[j];
if(i % prime[j] == 0) break ;
}
}
}
ll Calc_zt(int x){ ll res=0; while(x > 1){ res |= (1ll<<pos[from[x]]-1); x /= from[x]; } return res; }
struct Segment_Tree{
struct Node{ int l, r, sum, tag_1; ll zt, tag_2; } T[maxn << 2];
void Build(int k, int l, int r){
T[k].l = l, T[k].r = r, T[k].tag_1 = 1, T[k].tag_2 = 0;
if(l == r){ T[k].sum = A[l]; T[k].zt = Calc_zt(A[l]); return ; }
int mid = l+r >> 1;
Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
T[k].sum = 1ll*T[k<<1].sum * T[k<<1|1].sum % mod;
T[k].zt = T[k<<1].zt | T[k<<1|1].zt;
}
void Push_down(int k){
int lt = k<<1, rt = k<<1|1, len = T[k].r-T[k].l+1;
T[k].sum = 1ll*T[k].sum*Ksm(T[k].tag_1, len)%mod, T[k].zt |= T[k].tag_2;
T[lt].tag_1 = 1ll*T[lt].tag_1*T[k].tag_1 % mod;
T[rt].tag_1 = 1ll*T[rt].tag_1*T[k].tag_1 % mod;
T[lt].zt |= T[k].tag_2, T[lt].tag_2 |= T[k].tag_2;
T[rt].zt |= T[k].tag_2, T[rt].tag_2 |= T[k].tag_2;
T[k].tag_1 = 1, T[k].tag_2 = 0;
}
void Modify(int k, const int &ql, const int &qr, const int &x, const ll &st){
if(T[k].tag_1 != 1 || T[k].tag_2) Push_down(k);
int l = T[k].l, r = T[k].r;
if(ql > r || qr < l) return ;
if(ql <= l && r <= qr){
T[k].tag_1 = 1ll*T[k].tag_1*x % mod;
T[k].tag_2 |= st, T[k].zt |= st;
Push_down(k);
return ;
}
int mid = l+r >> 1;
Modify(k<<1, ql, qr, x, st);
Modify(k<<1|1, ql, qr, x, st);
T[k].sum = 1ll*T[k<<1].sum*T[k<<1|1].sum % mod;
T[k].zt = T[k<<1].zt | T[k<<1|1].zt;
}
int Query(int k, const int &ql, const int &qr){
if(T[k].tag_1 != 1 || T[k].tag_2) Push_down(k);
int l = T[k].l, r = T[k].r;
if(ql > r || qr < l) return 1;
if(ql <= l && r <= qr){ State |= T[k].zt; return T[k].sum; }
int mid = l+r >> 1, res = 1;
res = 1ll*res*Query(k<<1, ql, qr) % mod;
res = 1ll*res*Query(k<<1|1, ql, qr) % mod;
return res;
}
} seg_t;
int main(){
freopen("hanabi.in", "r", stdin);
freopen("hanabi.out", "w", stdout);
sieve(); N = read(), M = read();
for(reg int i = 1; i <= N; i ++) A[i] = read();
seg_t.Build(1, 1, N);
/*
int res = 0;
res = seg_t.Query(1, 233, 90000);
std::cout << res << std::endl;
for(reg int j = 1; j <= p_cnt; j ++) if(State & (1ll<<j-1)) res = 1ll*res*p_inv[j]%mod;
std::cout << State << std::endl;
*/
for(reg int i = 1; i <= M; i ++){
int op = read(), L = read(), R = read();
if(op == 1){ int x = read();
seg_t.Modify(1, L, R, x, Calc_zt(x));
} else{
State = 0;
int res = seg_t.Query(1, L, R);
for(reg int j = 1; j <= p_cnt; j ++) if(State & (1ll<<j-1)) res = 1ll*res*p_inv[j]%mod;
printf("%d
", res);
}
}
return 0;
}