思路:线段树区间乘法,维护$\phi(x_i)$,每次update w的质因子。
几个性质:
- 当$m$与$n$互质时有$\phi(m*n)==\phi(m)*\phi(n)$(这时使用单点修改)
- 当$k$是一个质数时,$\phi(k)==k-1$(这个代码里没有用到,但可以便于打表)
- $w$是一个质数,此时如果$\gcd(w,x_i)==w$则$\phi(w*x_i)==w*\phi(x_i)$。(如果一个区间里的$x_i$都满足这一点,可以区间修改)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 #include<cstdlib> 7 using namespace std; 8 9 #define mxp 114 //最大需要处理的数字 10 #define ll long long 11 #define rep(i,l,r) for(int i=l;i<=r;++i) 12 #define drep(i,r,l) for(int i=r;i>=l;--i) 13 #define maxn 114514 14 #define lson rt<<1 15 #define rson rt<<1|1 16 inline char nc(){ 17 static char buf[100010],*p1=buf,*p2=buf; 18 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 19 } 20 #ifndef ONLINE_JUDGE 21 #define nc() getchar() 22 #endif 23 inline int read(){ 24 int x=0,y=1; 25 char ch=nc(); 26 while(ch<'0'||ch>'9'){ 27 if(ch=='-')y=-y; 28 ch=nc(); 29 } 30 while(ch>='0'&&ch<='9'){ 31 x=10*x+(ch^48); 32 ch=nc(); 33 } 34 return x*y; 35 } 36 int n,m,cnt; 37 ll phi[255]; 38 const ll mod=998244353; 39 ll tr_phi[maxn<<2];//欧拉函数之和 40 ll seq[maxn]; 41 ll tag_mul[maxn<<2]; 42 bool isNP[514]; 43 ll prime[514]; 44 bool MUL[maxn<<2][514]; 45 inline void getprime(int x){ 46 rep(i,2,x){ 47 if(!isNP[i])prime[++cnt]=i; 48 rep(j,1,cnt){ 49 if(i*prime[j]>x)break; 50 isNP[i*prime[j]]=1; 51 if(i%prime[j]==0)break; 52 } 53 } 54 } 55 void pushdown(int l,int r,int rt){ 56 int mid=(l+r)>>1; 57 if(tag_mul[rt]!=1){ 58 tr_phi[lson]*=tag_mul[rt]; 59 tr_phi[lson]%=mod; 60 tr_phi[rson]*=tag_mul[rt]; 61 tr_phi[rson]%=mod; 62 tag_mul[lson]*=tag_mul[rt]; 63 tag_mul[lson]%=mod; 64 tag_mul[rson]*=tag_mul[rt]; 65 tag_mul[rson]%=mod; 66 tag_mul[rt]=1; 67 } 68 return; 69 } 70 void pushup(int rt){ 71 tr_phi[rt]=(tr_phi[lson]%mod+tr_phi[rson]%mod)%mod; 72 rep(i,2,mxp){ 73 MUL[rt][i]=MUL[lson][i]&MUL[rson][i]; 74 } 75 } 76 void build(int l,int r,int rt){ 77 tag_mul[rt]=1; 78 if(l==r){ 79 int dt=seq[l]; 80 tr_phi[rt]=phi[dt]; 81 rep(i,1,cnt){ 82 int cur_pm=prime[i]; 83 if(dt%cur_pm==0){ 84 MUL[rt][cur_pm]=1; 85 } 86 } 87 return; 88 } 89 int mid=(l+r)>>1; 90 build(l,mid,lson); 91 build(mid+1,r,rson); 92 pushup(rt); 93 } 94 void update(int L,int R,int l,int r,int rt,ll w){//这个更新的w只考虑质因子。 95 if(L<=l&&R>=r&&MUL[rt][w]){ 96 tr_phi[rt]*=w; 97 tag_mul[rt]*=w; 98 tr_phi[rt]%=mod; 99 tag_mul[rt]%=mod; 100 return; 101 } 102 if(l==r){ 103 tr_phi[rt]*=phi[w]; 104 tr_phi[rt]%=mod; 105 tag_mul[rt]=1; 106 MUL[rt][w]=1; 107 return; 108 } 109 pushdown(l,r,rt); 110 int mid=(l+r)>>1; 111 if(L<=mid)update(L,R,l,mid,lson,w); 112 if(mid+1<=R)update(L,R,mid+1,r,rson,w); 113 pushup(rt); 114 } 115 ll query(int L,int R,int l,int r,int rt){ 116 if(r<L||l>R)return 0; 117 if(L<=l&&r<=R)return tr_phi[rt]; 118 pushdown(l,r,rt); 119 int mid=(l+r)>>1; 120 return (query(L,R,l,mid,lson)%mod+query(L,R,mid+1,r,rson)%mod)%mod; 121 } 122 inline void getphi(int x){ 123 phi[0]=0,phi[1]=1; 124 rep(i,2,x)phi[i]=i; 125 rep(i,2,x){ 126 if(phi[i]==i){ 127 for(int j=i;j<=x;j+=i){ 128 phi[j]=phi[j]/i*(i-1); 129 } 130 } 131 } 132 } 133 int main(){ 134 getphi(125); 135 getprime(125); 136 n=read(),m=read(); 137 rep(i,1,n){ 138 seq[i]=read(); 139 } 140 build(1,n,1);bool flag=1; 141 rep(i,1,m){ 142 int op=read(),x=read(),y=read(); 143 144 if(op==1){ 145 flag? printf("%lld",query(x,y,1,n,1)),flag=0:printf("\n%lld",query(x,y,1,n,1)); 146 } 147 else if(op==0){ 148 ll up=read(); 149 int cur=1; 150 while(cur<=cnt){ 151 ll cur_p=prime[cur]; 152 while(up%cur_p==0){ 153 update(x,y,1,n,1,cur_p); 154 up/=cur_p; 155 } 156 if(up==1)break; 157 ++cur; 158 } 159 } 160 } 161 return 0; 162 }