题目链接:牛客23054 华华开始学信息学
题目描述
因为上次在月月面前丢人了,所以华华决定开始学信息学。十分钟后,他就开始学树状数组了。这是一道树状数组的入门题:
给定一个长度为N的序列A,所有元素初值为0。接下来有M次操作或询问:
操作:输入格式:1 D K,将A_D加上K。
询问:输入格式:2 L R,询问区间和,即
华华很快就学会了树状数组并通过了这道题。月月也很喜欢树状数组,于是给华华出了一道进阶题:
给定一个长度为N的序列A,所有元素初值为0。接下来有M次操作或询问:
操作:输入格式:1 D K,对于所有满足1≤i≤N,且i≡0(mod D),将Ai加上K。
询问:输入格式:2 L R,询问区间和,即
华华是个newbie,怎么可能会这样的题?不过你应该会吧。
输入描述
第一行两个正整数N、M表示序列的长度和操作询问的总次数。 接下来M行每行三个正整数,表示一个操作或询问。
输出描述
对于每个询问,输出一个非负整数表示答案。
题解
直接for(int i=x;i<=n;i+=x)add(i,y);最坏是o(n^m)=1e10,会爆掉
所以需要用个lazy[]进行分块统计小于sqrt(n)复杂度较大的那一部分y,
最后在算range_sum(x,y)的时候加上[x,y]中lazy[]数组的贡献
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
ll tree[100050],lazy[100050],n,m,ans;
ll lowbit(ll x)
{
return x&-x;
}
void add(ll i,ll x)
{
while(i<=n)
{
tree[i]+=x;
i+=lowbit(i);
}
}
ll sum(ll i)
{
ll res=0;
while(i>0)
{
res+=tree[i];
i-=lowbit(i);
}
return res;
}
ll range_sum(ll l,ll r)
{
return sum(r)-sum(l-1);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);
cin>>n>>m;
while(m--)
{
ll f,x,y;
cin>>f>>x>>y;
if(f==1){
if(x<=sqrt(n)){
lazy[x]+=y;
}
else{
for(ll i=x;i<=n;i+=x)
add(i,y);
}
}
else if(f==2) {
ans=range_sum(x,y);
for(ll i=1;i<=sqrt(n);i++)
ans+=(y/i-(x-1)/i)*lazy[i];
cout<<ans<<endl;
}
}
return 0;
}