牛客23054 華華開始學信息學 樹狀數組分塊

題目鏈接:牛客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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章