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