思路:
区间一个数的倍数的个数,我们可以 O(1) 算出的,问题在于要找的倍数有很多,考虑分块思想,把修改操作分为两类。
大于 sqrt(n) :
直接在树状数组中暴力 add
小于 sqrt(n) :
先记录下来,在每次查询操作时暴力计算
时间复杂度:
一次查询约是 O(sqrt(n))
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=1e5+10;
int n,m,lk;
ll c[N];
int lowbit(int x){
return x&(-x);
}
void add(int x,ll num){
for( ;x<=n;c[x]+=num,x+=lowbit(x));
}
ll query(int x){
ll re=0;
for( ;x>0;re+=c[x],x-=lowbit(x));
return re;
}
ll lazy[N];
int main(){
guo312;
cin>>n>>m; lk=sqrt(n);
ll op,l,r,d,k;
for(int i=1;i<=m;i++){
cin>>op;
if(op==1){
cin>>d>>k;
if(d<lk){
lazy[d]+=k;
}
else{
for(int j=d;j<=n;j+=d){
add(j,k);
}
}
}
else{
cin>>l>>r;
ll ans=query(r)-query(l-1);
for(int i=1;i<lk;i++){
ans+=(r/i-(l-1)/i)*lazy[i];
}
cout<<ans<<endl;
}
}
return 0;
}