![树状数组模板 - 卢凯宾 - 石门实验中学卢凯宾的博客 树状数组模板 - 卢凯宾 - 石门实验中学卢凯宾的博客](http://img.bimg.126.net/photo/I72LNIbeldoYcxOX5NBrfg==/4001448268935896526.jpg)
十进制数 | 对应的二进制数 | 二进制数最右端第一个1的位置 |
1 | 1 | 1 |
2 | 10 | 2 |
3 | 11 | 1 |
4 | 100 | 3 |
5 | 101 | 1 |
6 | 110 | 2 |
7 | 111 | 1 |
8 | 1000 | 4 |
9 | 1001 | 1 |
10 | 1010 | 2 |
//树状数组模板 by LKB 2016.8.4
//以下注释中涉及二进制数"第x位"的,
//均指该数的二进制形式右数第i位(从0开始算)
//例如11的二进制为1011,那么就有:
//11的二进制第0位为1,第1位为1,第2位为0,第3位为1
#include <iostream>
using namespace std;
const int maxn = 1000;
#define lowbit(x) (x & (-x))
int n, m;
int a[maxn]; //原始数组
int t[maxn]; //树状数组
int sum(int p) { //区间求和
//区间求和要把目标区间分成几个互相独立的小区间
//例如求sum(6),过程如下
//首先取t[6],它的取值范围只涉及a[6-lowbit(6)]..a[6]
//6的二进制是110,lowbit(6)=(10)2=2,故要取t[6-lowbit(6)]
//6-2=4的二进制是100,lowbit(4)=(100)2=4,4-lowbit(4)=0
//求和结束
int res = 0;
while (p) {
res += t[p]; //加上t[p]...t[lowbit(p)]的值
p -= lowbit(p); //指针左移lowbit(p)个位置
}
return res;
}
void add(int p, int v) { //单点修改
//例如修改第3个点,过程如下
//3的二进制是11,lowbit(3)=1
//3+lowbit(3)=4,故修改第4个点,4的二进制是100,lowbit(4)=4
//4+lowbit(4)=8,故修改第8个点,8的二进制是1000,
//....
while (p <= n) {
t[p] += v; //对涉及点p的所有点都修改
p += lowbit(p); //找下一个涉及点p的点
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < m; i++) {
char act;
cin >> act;
if (act == 'A') { //Add单点修改
int pos, delta;
cin >> pos >> delta; //把第pos个点的值增加delta
add(pos, delta);
}
if (act == 'S') { //Sum区间求和
int start, end;
cin >> start >> end; //求[start, end]区间内值的和
cout << sum(end) - sum(start - 1) << endl;
//原理类似前缀和
}
}
return 0;
}