列表

详情


NC23054. 华华开始学信息学

描述

因为上次在月月面前丢人了,所以华华决定开始学信息学。十分钟后,他就开始学树状数组了。这是一道树状数组的入门题:
给定一个长度为N的序列A,所有元素初值为0。接下来有M次操作或询问:
操作:输入格式:1 D K,将A_D加上K。
询问:输入格式:2 L R,询问区间和,即
华华很快就学会了树状数组并通过了这道题。月月也很喜欢树状数组,于是给华华出了一道进阶题:
给定一个长度为N的序列A,所有元素初值为0。接下来有M次操作或询问:
操作:输入格式:1 D K,对于所有满足的i,将A_i加上K。
询问:输入格式:2 L R,询问区间和,即
华华是个newbie,怎么可能会这样的题?不过你应该会吧。

输入描述

第一行两个正整数N、M表示序列的长度和操作询问的总次数。
接下来M行每行三个正整数,表示一个操作或询问。

输出描述

对于每个询问,输出一个非负整数表示答案。

示例1

输入:

10 6
1 1 1
2 4 6
1 3 2
2 5 7
1 6 10
2 1 10

输出:

3
5
26

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 966ms, 内存消耗: 2424K, 提交时间: 2019-03-10 00:27:28

#include<bits/stdc++.h>
#define low(x) x&-x
#define ll long long
using namespace std;
const int maxn=1e5+10;
ll c[maxn],a[maxn];
void up(int i,int v,int n)
{
	for(;i<=n;i+=low(i))c[i]+=v;
}
ll qu(int i)
{
	ll res=0;
	for(;i;i-=low(i))res+=c[i];
	return res;
}	
int n,k,x,d,tp,T;
ll gao(int m)
{
	ll res=qu(m);
	int N=min(m,T);
	for(int i=1;i<=N;i++)
	res+=1ll*m/i*a[i];
	return res;
}
int main()
{
	scanf("%d%d",&n,&k);
	T=(int)sqrt(1.0*n*2);
	while(k--)
	{
		scanf("%d%d%d",&tp,&d,&x);
		if(tp==1)
		{
			if(d>=T)
			for(int i=d;i<=n;i+=d)up(i,x,n);
			else a[d]+=x;
		}
		else
		printf("%lld\n",gao(x)-gao(d-1));
	}
}

C++(clang++ 11.0.1) 解法, 执行用时: 423ms, 内存消耗: 2360K, 提交时间: 2022-08-05 09:09:26

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int c[N],a[N],n,m;
inline int lowbit(int x)
{
	return x&-x;
}
void add(int x,int y)
{
	for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
int ask(int x)
{
	int ans=0;
	for(;x;x-=lowbit(x)) ans+=c[x];
	return ans;
}
signed main (void)
{
	cin>>n>>m;
	int len=sqrt(n);
	while(m--)
	{
		int op,x,y;
		cin>>op>>x>>y;
		if(op==1)
		{
			if(x<=len) a[x]+=y;
			else for(int i=x;i<=n;i+=x) add(i,y);
		}
		else{
			int ans=ask(y)-ask(x-1);
			for(int i=1;i<=len;i++) ans+=(y/i-(x-1)/i)*a[i];
			cout<<ans<<endl;
		}
	}
}

上一题