目录
基本概念
树状数组 (Fenwick Tree / Binary Indexed Tree)是一种高效的数据结构,主要用于解决以下问题:
-
动态维护前缀和
-
支持单点更新和前缀查询
-
某些情况下可以扩展为支持区间更新和区间查询
基本特性
-
时间复杂度:
-
单点更新: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
题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某区间每一个数加上 x;
求出某一个数的值。
输入格式
第一行包含两个整数 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;
}