树状数组题目(求和,树状数组 1)

这篇博客介绍了树状数组和线段树在求和操作中的应用,包括基本概念、操作方法以及AC代码。文章通过两道题目详细解释了如何使用这两种数据结构解决区间修改和区间查询的问题,提供了清晰的思路和模板代码,适合初学者学习。
摘要由CSDN通过智能技术生成

序言

今天老师教了树状数组,并要求我们做题所以水了水题,要学树状数组的,点这——>树状数组,然后老师在下午时,又叫我们用线段树写 求和光明OJ的题,所以我来补代码了

First Problem求和

时间限制: 1000 ms 空间限制: 131072 KB

题目描述

输入一个数列A1,A2….An(1<=N<=100000),在数列上进行M(1<=M<=100000)次操作,操作有以下两种:

  1. 格式为 C C C I I I X X X,其中 C C C为字符“ C C C”, I I I X X X ( 1 ≤ I ≤ N , X ≤ 10000 ) (1\le I \le N,X\le 10000) (1IN,X10000)都是整数,表示把把 a I a_I aI改为 X X X
  2. 格式为 Q Q Q L L L R R R,其中 Q Q Q为字符“ Q Q Q”, L L L R R R表示询问区间为 [ L , R ] [L,R] [L,R] ( 1 ≤ L < = R ≤ N ) (1\le L<=R\le N) (1L<=RN),表示询问 A L + … + A R A_L+…+A_R AL++AR的值。

输入

第一行输入 N ( 1 ≤ N ≤ 100000 ) N(1\le N\le 100000) N(1N100000),表述数列的长度,接下来 N N N行,每行一个整数(绝对值不超过 10000 10000 10000)依次输入每个数;接下来输入一个整数 M ( 1 ≤ M ≤ 100000 ) M(1\le M\le 100000) M(1M100000),表示操作数量,接下来 M M M行,每行为 C C C I I I X X X或者 Q Q Q L L L R R R

输出

对于每个 Q Q Q L L L R R R 的操作输出答案。

样例输入

5
1
2
3
4
5
3
Q 2 3
C 3 9
Q 1 4

样例输出

5
16

思路

这题是模板题呀,我们只需注意是将 a i a_i ai改为 x x x,而不是加 x x x,我当时脑子没转过来
所以 a d d add add就应该是 a d d ( i , x − l [ i ] ) add(i,x-l[i]) add(i,xl[i]), l [ i ] l[i] l[i]是原来的值,最后将 l [ j ] = x l[j]=x l[j]=x就行了。询问,大家都会吧,就不水了

AC Code(树状数组)

#include<bits/stdc++.h>
using namespace std;
int x,y,ans,n,m,b[1000000];
char ph;
int a[1000000];
int max(int x,int y){
	return x>y?x:y;
}
void make(int l,int r,int i){
	if(l==r){
		a[i]=b[l];
		return ;
	}
	int m=(l+r)/2;
	make(l,m,i<<1);
	make(m+1,r,i<<1|1);
	a[i]=a[i<<1]+a[i<<1|1];
}
void qry(int i,int l,int r){
	if(r<x||l>y) return ;
	if(l>=x&&r<=y){
		ans+=a[i]; 
		return;
	}
	int m=(l+r)>>1;
	qry(i<<1,l,m);
	qry(i<<1|1,m+1,r);
}
void add(int i,int l,int r){
	if(l==r){a[i]=y;return ;}
	int m=(l+r)>>1;
	if(x<=m) add(i<<1,l,m);
	else add(i<<1|1,m+1,r);
	a[i]=a[i<<1]+a[i<<1|1];
}
int main(){
	ios::sync_with_stdio(false);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	make(1,n,1);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		ans=0;
		scanf("%s%d%d",&ph,&x,&y);
		if(ph=='Q'){
			qry(1,1,n);
			printf("%d\n",ans);
		}
		else add(1,1,n);
	}
	return 0;
}

Second problem 【模板】树状数组 1

Go luogu problem

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  • 将某一个数加上 x x x

  • 求出某区间每一个数的和

输入格式

第一行包含两个正整数 n , m n,m n,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i 项的初始值。

接下来 m m m 行每行包含 3 3 3 个整数,表示一个操作,具体如下:

  • 1 x k 含义:将第 x x x 个数加上 k k k

  • 2 x y 含义:输出区间 [ x , y ] [x,y] [x,y] 内每个数的和

输出格式

输出包含若干行整数,即为所有操作 2 2 2 的结果。

样例

样例输入1
5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
样例输出1
14
16

提示

数据范围:

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 8 1 \le n \le 8 1n8 1 ≤ m ≤ 10 1\le m \le 10 1m10
对于 70 % 70\% 70% 的数据, 1 ≤ n , m ≤ 1 0 4 1\le n,m \le 10^4 1n,m104
对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 5 × 1 0 5 1\le n,m \le 5\times 10^5 1n,m5×105

样例说明:

故输出结果14、16

思路

这道题比上面那道还模板,给第 x x x个数加上 k k k直接 a d d ( x , k ) add(x,k) add(x,k)就行,十分水。
求和就简单讲一讲,算 1 − n 1-n 1n大家都会吧,就

int q(int x){//表示1~x的和
	int ans=0;//统计和
	while(x!=0){//表示不出范围也可以写成x>0
		ans+=a[x];//a[x]表示树状数组下标为[x]的数
		x-=lowbit(x);//对于每个数的lowbit为这个数二进制的最后1个'1'
	}
	return ans;//返回前缀和
}

有了前缀和就可以求 a l , r a_{l,r} al,r的总值, a l , r = q ( r ) − q ( l − 1 ) a_{l,r}=q(r)-q(l-1) al,r=q(r)q(l1)如果记不得是 r − ( l − 1 ) r-(l-1) r(l1)还是 ( l − 1 ) − r (l-1)-r (l1)r
可以写成 a i , j = a b s ( q ( l − 1 ) − q ( r ) ) a_{i,j}=abs(q(l-1)-q(r)) ai,j=abs(q(l1)q(r))取个绝对值

AC Code

#include<bits/stdc++.h>
using namespace std;
int a[500001],n,m,l;
int lowbit(int x){
	return x&(-x);
}
int q(int x){
	int ans=0;
	while(x!=0){
		ans+=a[x];
		x-=lowbit(x);
	}
	return ans;
}
void add(int x,int k){
	while(x<=n){
		a[x]+=k;
		x+=lowbit(x);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		cin>>l;
		add(i,l);
	}
	for(int i=1;i<=m;i++){
		int r;
		int j,k;
		scanf("%d%d%d",&r,&j,&k);
		if(r==2){
			int sum=q(k)-q(j-1);
			printf("%d\n",sum);
		}else{
			add(j,k);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值