1 // HDU5634 Rikka with Phi 线段树
2 // 思路:操作1的时候,判断一下当前区间是不是每个数都相等,在每个数相等的区间上操作。相当于lazy,不必更新到底。
3
4
5 #include <bits/stdc++.h>
6 using namespace std;
7 #define clc(a,b) memset(a,b,sizeof(a))
8 #define inf 0x3f3f3f3f
9 #define lson l,mid,rt<<1
10 #define rson mid+1,r,rt<<1|1
11 const int N = 300010;
12 const int MOD = 1e9+7;
13 #define LL long long
14 double const pi = acos(-1);
15 void fre() {
16 freopen("in.txt","r",stdin);
17 }
18 // inline int r() {
19 // int x=0,f=1;char ch=getchar();
20 // while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
21 // while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar();}return x*f;
22 // }
23 const int MAXM=1e7+10;
24 LL euler[10000010];
25 int a[N];
26 void Geteuler()
27 {
28 memset(euler, 0, sizeof(euler));
29 euler[1] = 1;
30 for(LL i = 2; i < MAXM; i++) if(!euler[i])
31 for(LL j = i; j < MAXM; j += i){
32 if(!euler[j]) euler[j] = j;
33 euler[j] = euler[j] / i * (i-1);
34 }
35 }
36
37 struct tree{
38 int l,r;
39 LL sum,lazy;
40 }t[N<<2];
41
42 void pushup(int rt){
43 t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
44 if(t[rt<<1].lazy==t[rt<<1|1].lazy) t[rt].lazy=t[rt<<1].lazy;
45 else t[rt].lazy=0;
46 }
47
48 void pushdown(int rt){
49 if(t[rt].lazy){
50 t[rt<<1].lazy=t[rt<<1|1].lazy=t[rt].lazy;
51 t[rt<<1].sum=(t[rt<<1].r-t[rt<<1].l+1)*t[rt<<1].lazy;
52 t[rt<<1|1].sum=(t[rt<<1|1].r-t[rt<<1|1].l+1)*t[rt<<1|1].lazy;
53 t[rt].lazy=0;
54 }
55 }
56 void build(int rt,int x,int y){
57 t[rt].l=x;
58 t[rt].r=y;
59 if(x==y){
60 t[rt].sum=a[x];
61 t[rt].lazy=a[x];
62 return;
63 }
64 int mid=(x+y)>>1;
65 build(rt<<1,x,mid);
66 build(rt<<1|1,mid+1,y);
67 pushup(rt);
68 }
69
70 void update1(int rt,int x,int y){
71 if(t[rt].lazy&&t[rt].l==x&&t[rt].r==y){
72 t[rt].sum=(t[rt].r-t[rt].l+1)*euler[t[rt].lazy];
73 t[rt].lazy=euler[t[rt].lazy];
74 return;
75 }
76 pushdown(rt);
77 int mid=(t[rt].l+t[rt].r)>>1;
78 if(y<=mid) update1(rt<<1,x,y);
79 else if(x>mid) update1(rt<<1|1,x,y);
80 else {
81 update1(rt<<1,x,mid);
82 update1(rt<<1|1,mid+1,y);
83 }
84 pushup(rt);
85 }
86
87 void update2(int rt,int x,int y,int z){
88 if(t[rt].l==x&&t[rt].r==y){
89 t[rt].lazy=z;
90 t[rt].sum=1LL*z*(t[rt].r-t[rt].l+1);
91 return;
92 }
93 pushdown(rt);
94 int mid=(t[rt].l+t[rt].r)>>1;
95 if(y<=mid) update2(rt<<1,x,y,z);
96 else if(x>mid) update2(rt<<1|1,x,y,z);
97 else {
98 update2(rt<<1,x,mid,z);
99 update2(rt<<1|1,mid+1,y,z);
100 }
101 pushup(rt);
102 }
103
104 LL query(int rt,int x,int y){
105 if(t[rt].l==x&&t[rt].r==y){
106 return t[rt].sum;
107 }
108 pushdown(rt);
109 int mid=(t[rt].l+t[rt].r)>>1;
110 if(y<=mid) return query(rt<<1,x,y);
111 else if(x>mid) return query(rt<<1|1,x,y);
112 else{
113 return query(rt<<1,x,mid)+query(rt<<1|1,mid+1,y);
114 }
115 }
116 int main(){
117 // fre();
118 Geteuler();
119 int T;
120 scanf("%d",&T);
121 while(T--){
122 int n,m;
123 scanf("%d%d",&n,&m);
124 for(int i=1;i<=n;i++) scanf("%d",&a[i]);
125 build(1,1,n);
126 while(m--){
127 int op,x,y,z;
128 scanf("%d%d%d",&op,&x,&y);
129 if(op==1) update1(1,x,y);
130 else if(op==2) {
131 scanf("%d",&z);
132 update2(1,x,y,z);
133 }
134 else {
135 // cout<<"sdf"<<endl;
136 LL ans=query(1,x,y);
137 printf("%I64d\n",ans);
138 }
139 }
140 }
141 return 0;
142 }