思路:
分块,树状数组
直接树状数组进行add操作
for(int i=d;i<=n;i+=d))add(d,k)
时间复杂度起码是O(nm)=1e10,肯定t
这个时候我们可以考虑进行分块操作
对于d小于等于√n的我们就存到一个lazy数组里
大于√n的我们就直接进行树状数组的add操作
这样的话根据上面那个循环我们add操作时间复杂度差不多是log2(n)(树状数组本身add操作为logn)
而lazy操作为O1
查询区间和的时候
lazy操作为logn(直接扫一遍下标小于logn的数)
得树状数组和也为logn
这样就能大大优化时间复杂度得到答案了
AC代码:
#include <iostream>
#include <math.h>
#define IOS ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll a[N];
ll lazy[N];
ll c[N];
int n,m;
int lower_bit(int x)
{
return x&(-x);
}
ll getsum(int x)
{
ll cnt=0;
while(x>0)
{
cnt+=c[x];
x-=lower_bit(x);
}
return cnt;
}
void add(int x,ll k)
{
while(x<=n)
{
c[x]+=k;
x+=lower_bit(x);
}
return;
}
int main()
{
IOS;
cin>>n>>m;
while(m--)
{
int q;
cin>>q;
if(q==1)
{
int d,k;
cin>>d>>k;
if(d<=sqrt(n))
{
lazy[d]+=k;
}
else
{
for(int i=1; i*d<=n; i++) //logn时间复杂度
{
add(d*i,k);
}
}
}
else
{
int l,r;
cin>>l>>r;
ll ans=getsum(r)-getsum(l-1);
for(int i=1; i<=sqrt(n); i++) //logn时间复杂度
{
ans+=(r/i-(l-1)/i)*lazy[i];
}
cout<<ans<<endl;
}
}
return 0;
}