分析
由于(a_i=1或2)时(d(a_i)=a_i),且其余情况修改后答案只会越来越小,
考虑用树状数组维护区间和,用并查集跳过(a_i=1或2)的情况
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1000011,M=300011;
typedef long long lll;
int n,m,a[M],f[M],Cnt; lll c[M];
int prime[M],d[N],mc[N]; bool v[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void Pro(int n){
d[1]=1,mc[1]=1;
for (rr int i=2;i<=n;++i){
if (!v[i]) prime[++Cnt]=i,d[i]=mc[i]=2;
for (rr int j=1;j<=Cnt&&prime[j]<=n/i;++j){
v[i*prime[j]]=1;
if (i%prime[j]==0){
mc[i*prime[j]]=mc[i]+1;
d[i*prime[j]]=d[i]/mc[i]*(mc[i]+1);
break;
}
mc[i*prime[j]]=2,
d[i*prime[j]]=d[i]<<1;
}
}
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]); }
inline void update(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline lll query(int l,int r){
rr lll ans=0; --l;
for (;r>l;r-=-r&r) ans+=c[r];
for (;l>r;l-=-l&l) ans-=c[l];
return ans;
}
signed main(){
n=iut(),m=iut(),Pro(N-11),f[n+1]=n+1;
for (rr int i=1;i<=n;++i) c[i]=c[i-1]+(a[i]=iut());
for (rr int i=n;i;--i) f[i]=i,c[i]-=c[i&(i-1)];
for (rr int z,l,r;m;--m){
z=iut(),l=iut(),r=iut();
if (z==2) print(query(l,r)),putchar(10);
else for (rr int i=getf(l);i<=r;){
update(i,d[a[i]]-a[i]),a[i]=d[a[i]];
f[i]=i+(a[i]<3),i=(getf(i)==i)?i+1:f[i];
}
}
return 0;
}