題目鏈接:牛客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;
}