【树状数组】
顾名思义:本质是数组,逻辑上是被构造出来的二叉树,方便求前缀和,以及更新元素值
关键:设原数组为A,设构造出来的树状数组为 C,令
C i = A i-lowbit(i) + 1 + A i-lowbit(i) + 2 + .......... + Ai , 其中lowbit(i) = i & (-i)
所以
操作1:求前缀和 Si = Ci + Ci-lowbit(i) + ...... 直到 C 的下标 index = i - lowbit(i) = 1
操作2:元素A[x] 的值加上 y ,需要更新包含A[x] 的区间:
C[x] = C[x] + y
x = x + lowbit(x) C[x] = C[ x ] + y
........
直到 x > n (n 为元素个数)
可以得以上两个操作的时间复杂度均为 O( logn )
【应用】
求逆序对
【优化】
【模板】
/*树状数组模板注意数组C[]下标是从1开始by chsobin*/const int maxn = 32005;
int c[maxn];
void init(){
memset(c, 0, sizeof(c));
}
int lowbit(int x){
return x & (-x);
}
void update(int x, int add){
while(x<=maxn){
c[x] += add;
x += lowbit(x);
}
}
int getsum(int x){
int s = 0;
while(x > 0){
s += c[x];
x -= lowbit(x);
}
return s;
}
【题目】
hdu1541

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 32005;
int c[maxn];
int ans[maxn];
void init(){
memset(c, 0, sizeof(c));
memset(ans, 0, sizeof(ans));
}
int lowbit(int x){
return x & (-x);
}
void update(int x, int add){
while(x<=maxn){
c[x] += add;
x += lowbit(x);
}
}
int getsum(int x){
int s = 0;
while(x > 0){
s += c[x];
x -= lowbit(x);
}
return s;
}
int main(){
int n, x, y;
while(~scanf("%d", &n)){
init();
for(int i=0;i<n;++i){
scanf("%d%d", &x, &y);
x++; //很重要,被这个坑了,一直超时
ans[getsum(x)]++;
update(x, 1);
}
for(int i=0;i<n;++i) printf("%d\n", ans[i]);
}
return 0;
}
hdu4970
树状数组区间更新
参考自http://blog.csdn.net/idealism_xxm/article/details/51051342
【参考】
来源:https://www.cnblogs.com/chsobin/p/8323884.html
