题干:
思路:
区间查询、区间修改可以是使用考虑线段树,每个节点包含2个元素,中和和最高值。因为数据是在1e6的范围内,对于d()的操作次数是不多的,可以提前处理完,对于小于等于2的数据就不用再处理了。
代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int MAXN=1e6;
const int mod=6e5;
const int N=2000050;
int t,n,m;
ll a[N];
int f[MAXN+1];
struct node{
ll sum,l,r,maxv;
}s[N];
void test(int x){
cout<<x<<endl;
}
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
void push_up(int p){
s[p].sum=s[p<<1].sum+s[p<<1|1].sum;
s[p].maxv=max(s[p<<1].maxv,s[p<<1|1].maxv);
}
void update(int x,int y,int p,int l,int r){
if(s[p].maxv<=2) return;
if(l==r){
a[l]=f[a[l]];
s[p].sum=s[p].maxv=a[l];
return;
}
int mid=l+(r-l)/2;
if(x<=mid){
update(x,y,p<<1,l,mid);
}
if(mid<y){
update(x,y,p<<1|1,mid+1,r);
}
push_up(p);
}
ll query(int x,int y,int p,int l,int r){
ll ans=0;
if(x<=l&&r<=y) return s[p].sum;
int mid=l+(r-l)/2;
if(x<=mid){
ans+=query(x,y,p<<1,l,mid);
}
if(y>mid){
ans+=query(x,y,p<<1|1,mid+1,r);
}
return ans;
}
void build(int p,int l,int r){
if(l==r){
s[p].sum=a[l];
s[p].maxv=a[l];
return;
}
int mid=l+(r-l)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
push_up(p);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
n=read();
m=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
build(1,1,n);
// for(int i=1;i<=n;i++){
// cout<<i<<": "<<s[i].sum<<endl;
// }
for(int i=2;i<=MAXN;i++){
for(int j=i;j<=MAXN;j+=i) f[j]++;
f[i]++;
}
while(m--){
int t,x,y;
t=read();
x=read();
y=read();
//cin>>t>>x>>y;
if(t==1){
update(x,y,1,1,n);
}
else{
cout<<query(x,y,1,1,n)<<endl;
}
}
return 0;
}