树状数组
Handezheng · · 算法·理论
树状数组
明确
树状数组仅能实现两个功能:
- 单点修改
- 区间查询
表示
如图,以 4 为例,二进制是100,它是010(2)和011(3)的父亲,是1000(8)的儿子
那么,对于c,它的父亲是二进制下,最后一个 1 (lowbit(c)) + 1
区间查询
令c[i]等于它管辖的数的和
以7为例,即111 求区间[1,7]就等于c[111] +c[110]+c[100]
下附模板:
int find(int u){
int ans = 0;
while(u){
ans += c[u];
u -= u&-u;//去掉最后一个零
}
return ans;
}
求区间[l,r]即求[1,r] - [1,l - 1]
单点修改
注意:修改时应将其父亲,父亲的父亲...都修改
模板:
void add(int u,int x){//将第u个数增加x
while(u <= n){
c[u] += x;
u += u&-u;//将最后一个零进一位
}
}
谨记
相对于对于树状数组的两个功能,更重要的是将题意转化为树状数组能够实现的功能
如 树状数组2 的思路就是维护一个差分数组,将区间修改转化为两个区间端点的单点修改,将单点查询转化为查分数组的前缀和
好题
类似的树状数组题目还有 P1083 [NOIP2012 提高组] 借教室 、 P1908 逆序对 等
P3372 【模板】线段树 1
特别的,对于 P3372 【模板】线段树 1 中的区间修改、区间求和问题:
我们可以维护两个树状数组,
第一个如树状数组2中的,是一个查分的树状数组,这样就实现了区间修改功能
而在查询时,现将查分树状数组进行前缀和,实现单点查询,再维护一个树状数组,用以前缀和第一个树状数组的前缀和,这样就实现了区间查询的功能