数据结构进阶——树状数组

目录

基本概念

基本特性

基本操作实现

关键操作(lowbit)

单点更新(Update)

前缀查询(Query)

应用模板

P3374 【模板】树状数组 1

P3368 【模板】树状数组 2


基本概念

树状数组 (Fenwick Tree / Binary Indexed Tree)是一种高效的数据结构,主要用于解决以下问题:

  1. 动态维护前缀和

  2. 支持单点更新和前缀查询

  3. 某些情况下可以扩展为支持区间更新和区间查询

基本特性

  • 时间复杂度

    • 单点更新:O(log n)

    • 前缀查询:O(log n)

  • 空间复杂度:O(n)

基本操作实现

关键操作(lowbit)

int lowbit(int x){
	return x&-x;
}

单点更新(Update)

void update(int x,int data){
	while(x<=n){
		tree[x]+=data;
		x+=lowbit(x);
	}
}

前缀查询(Query)

long long query(int x){
	long long res=0;
	while(x>=1){
		res+=tree[x];
		x-=lowbit(x);
	}
	return res;
}

应用模板

P3374 【模板】树状数组 1

题目描述

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

  • 将某一个数加上 x

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

输入格式

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

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

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

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

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

输出格式

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

输入输出样例

输入 #1                                                            输出 #1

5  5                                                                  14
1  5  4  2  3                                                      16
1  1  3
2  2  5
1  3  -1
1  4  2
2  1  4

说明/提示

【数据范围】

对于 30% 的数据,1≤n≤8,1≤m≤10;
对于 70% 的数据,1≤n,m≤104;
对于 100% 的数据,1≤n,m≤5×105。

数据保证对于任意时刻,a 的任意子区间(包括长度为 1 和 n 的子区间)和均在 [−231,231) 范围内。

#include<bits/stdc++.h>
using namespace std;
int a[500005],tree[500005],n,m;
int lowbit(int x){
	return x&-x;
}
void update(int x,int data){
	while(x<=n){
		tree[x]+=data;
		x+=lowbit(x);
	}
}
long long query(int x){
	long long res=0;
	while(x>=1){
		res+=tree[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		update(i,a[i]);
	}
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		if(a==1) update(b,c);
		else cout<<query(c)-query(b-1)<<endl;
	}
	return 0;
}

P3368 【模板】树状数组 2

题目描述

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

  1. 将某区间每一个数加上 x;

  2. 求出某一个数的值。

输入格式

第一行包含两个整数 N、M,分别表示该数列数字的个数和操作的总个数。

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

接下来 M 行每行包含 2 或 4个整数,表示一个操作,具体如下:

操作 1: 格式:1 x y k 含义:将区间 [x,y] 内每个数加上 k;

操作 2: 格式:2 x 含义:输出第 x 个数的值。

输出格式

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

输入输出样例

输入 #1复制

2 2 3
1 1
2 2
1 2 

输出 #1复制

1
1
4

数据规模与约定

对于 30% 的数据:N≤8,M≤10;

对于 70% 的数据:N≤10000,M≤10000;

对于 100% 的数据:1≤N,M≤500000,1≤x,y≤n,保证任意时刻序列中任意元素的绝对值都不大于 230。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll arr[500005],n,m,temp;
inline int lowbit(int x){
	return x&-x;
}
inline void update(int x,int data){
	while(x<=n){
		arr[x]+=data;
		x+=lowbit(x);
	}
}
inline ll ask(int x){
	ll res=0;
	while(x>=1){
		res+=arr[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>temp;
		update(i,temp);
		update(i+1,-temp);
	}
	while(m--){
		int a,b,c,d;
		cin>>a;
		if(a==1){
			cin>>b>>c>>d;
			update(b,d);
			update(c+1,-d);
		}
		else{
			cin>>b;
			cout<<ask(b)<<endl;
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值