【练习-2】树状数组-模板二(区间修改,单点查询)

直接放题目然后再进行解释:
树状数组:
1.单点修改,区间查询
2.区间修改,单点查询
3.区间修改,区间查询

区间修改,单点查询

Description
给定数列a[1],a[2],…,a[n] ,你需要依次进行 q 个操作,操作有两类:

1 l r x:给定 l,r,x,对于所有i∈[l,r],将 a[i] 加上 x(换言之,将 a[l],a[l+1],…,a[r] 分别加上 x);
2 i:给定 i ,求 a[i] 的值。
Input
第一行包含 2 个正整数 n,q,表示数列长度和询问个数。保证1≤n,q≤106 。
第二行 n 个整数 a[1],a[2],…,a[n],表示初始数列。保证|a[i]|≤106 。
接下来 q 行,每行一个操作,为以下两种之一:

1 l r x:对于所有 i∈[l,r],将a[i]加上x;
2 i:给定 i,求 a[i] 的值。
保证 1≤l≤r≤106, |x|≤106。

Output
对于每个 2 i 操作,输出一行,每行有一个整数,表示所求的结果。

Samples
Input

3 2
1 2 3
1 1 3 0
2 2
Output
2
Hint
对于所有数据,1≤n,q≤106 , |a[i]|≤106, 1≤l≤r≤n, |x|≤106

AC code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read() {char ch = getchar(); int x = 0, f = 1;while(ch < '0' || ch > '9') {if(ch == '-') f = -1;ch = getchar();} while('0' <= ch && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();} return x * f;}
int n,q,a,b,c,k,x,now,last;
ll t[1000005];
ll lowbit(ll x)	{return x&(-x);}
void add(ll x,ll w)
{
	while(x<=n)
	{
		t[x]+=w;
		x += lowbit(x);	
	}	
	return ;
} 
ll sum(ll x)
{
	ll s=0;
	while(x>0)
	{
		s+=t[x];
		x -= lowbit(x);
	}
	return s;
}
int main()
{
	n=read();
	q=read();
	for(ll i=1;i<=n;i++)
	{
		now = read();
		add(i,now-last);
		last = now;
	}
	while(q--)
	{
		k =read();
		if(k==1)
		{
			a=read();
			b=read();
			c=read();
			add(a,c);
			add(b+1,-c);
		}
		if(k==2)
		{
			x = read();
			printf("%lld\n",sum(x));	
		}
	}
	return 0;	
}

前面的三个函数lowbit,add,sum和单点修改,区间查询是一样的,不再多做解释,可以在上一个练习查看。
要做到区间修改,我们能想到的省时间的做法是什么—差分前缀和
打个比方,也就是说我们要给区间[1,3]的每个数加上4,我们只需要给差分数组的a[1]加上4,给差分数组的a[4]减去4

a[1]+=4;
a[4]-=4;

这是因为差分在做前缀和的时候就会给每个数都加上这个数(4,0,0,-4 --> 4,4,4,0)

	for(ll i=1;i<=n;i++)
	{
		now = read();
		add(i,now-last);
		last = now;
	}

最开始输入的时候就要做好差分,确保这个数组是一个差分数组

			a=read();
			b=read();
			c=read();
			add(a,c);
			add(b+1,-c);

修改区间的时候也要做好差分,所以是两个add。

			x = read();
			printf("%lld\n",sum(x));

最后要查询哪一个位置就直接输出哪个位置的sum(x)。
因为我们在之前说过的(单点修改,区间查询)sum函数最终得到的是前缀和,那么差分数组的前缀和,某个位置的值,就是该位置实际的值。

以上只是鄙人的拙见,如果有错误、不足之处,还请指正。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值