题意:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201127223751584.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDE3ODczNg==,size_16,color_FFFFFF,t_70)
解法:
存在性质:x变为d(x),最多变6次之后,x<=2.
当x<=2时,d(x)=x,之后x就不会再变了.
解法1:
线段树维护区间max,当区间max<=2的之后,就不修改了.
区间和线段树也可以直接维护.
解法2:
因为当x<=2时,d(x)=x,之后x就不会再变了,
那么可以考虑存一个链表,每次暴力修改,当a[i]<=2的时候,将其从链表中删掉.
可以用并查集做:令pre[i]表示i位置右边的下一个节点(包含i),删除很方便.
区间和考虑用前缀和快速计算,因为值会修改,需要动态维护前缀和,需要树状数组.
ps:
代码用的是解法2.
code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e6+5;
int pre[maxm];
int d[maxm];
int a[maxm];
int n,m;
struct BIT{
int c[maxm];
int lowbit(int i){return i&-i;}
void add(int i,int t){while(i<maxm)c[i]+=t,i+=lowbit(i);}
int ask(int i){int ans=0;while(i)ans+=c[i],i-=lowbit(i);return ans;}
}T;
int ffind(int x){
return pre[x]==x?x:pre[x]=ffind(pre[x]);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
for(int i=1;i<maxm;i++){
for(int j=i;j<maxm;j+=i){
d[j]++;
}
}
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
T.add(i,a[i]);
}
for(int i=1;i<=n+1;i++){
pre[i]=i;
}
while(m--){
int op,l,r;cin>>op>>l>>r;
if(op==1){
l=ffind(l);
while(l<=r){
T.add(l,-a[l]);
a[l]=d[a[l]];
T.add(l,a[l]);
if(a[l]<=2){
pre[l]=ffind(l+1);
}
l=ffind(l+1);
}
}else if(op==2){
cout<<T.ask(r)-T.ask(l-1)<<endl;
}
}
return 0;
}