树状数组
来源:互联网 发布:家庭理财记账软件 编辑:程序博客网 时间:2024/05/31 18:54
士兵杀敌(二)(南理116)
时间限制:1000 ms | 内存限制:65535 KB
难度:5
描述
南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的。
小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。
南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。
输入
只有一组测试数据
第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数。(1<M<100000)
随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)
随后的M行每行是一条指令,这条指令包含了一个字符串和两个整数,首先是一个字符串,如果是字符串QUERY则表示南将军进行了查询操作,后面的两个整数m,n,表示查询的起始与终止士兵编号;如果是字符串ADD则后面跟的两个整数I,A(1<=I<=N,1<=A<=100),表示第I个士兵新增杀敌数为A.
输出
对于每次查询,输出一个整数R表示第m号士兵到第n号士兵的总杀敌数,每组输出占一行
样例输入
5 6
1 2 3 4 5
QUERY 1 3
ADD 1 2
QUERY 1 3
ADD 2 3
QUERY 1 2
QUERY 1 5
样例输出
6
8
8
20
#include<stdio.h>
int tree[1000005];//tree为树状数组
void swap(int *a, int *b) {
int *temp = a;
a = b;
b = temp;
}
int lowBit(int x) {
return x & (-x); //访问树状数组
}
void modify(int pos, int num, int N) {
while (pos <= N) {//从1开始访问树状数组并增加值
tree[pos] += num;
pos += lowBit(pos);
}//traverse遍历
}
int getSum(int pos) {
int sum = 0;
while (pos > 0) {//求1到pos的和
sum += tree[pos];
pos -= lowBit(pos);
}
return sum;
}
int main() {
int N, M, kill;
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; i++) {
scanf("%d", &kill);
modify(i, kill, N);
}
int m, n;
char order[10];
while (M--) {
scanf("%s", order);
if (order[0] == 'Q') {
scanf("%d%d", &m, &n);
if (m > n) swap(&m, &n);
printf("%d\n", getSum(n)-getSum(m-1));
}else {
scanf("%d%d", &m, &n);
modify(m, n, N);
}
}
return 0;
}
1.图一
1.图二
(图片网上找的)
1.树状数组C从与普通数组A的关系:
C[1] = A[1];
C[2] = C[1] + A[2] = A[1] + A[2];
C[3] = A[3];
C[4] = C[2] + C[3] + A[4] = C[1] + A[2] + A[3] + A[4] = A[1] + A[2] + A[3] + A[4];
C[5] = A[5];
C[6] = C[5] + A[6] = A[5] + A[6];
C[7] = A[7];
C[8] = C[4] + C[6] + C[7] + A[8] = C[2] + C[3] + A[4] + C[5] + A[6] + A[7] + A[8] = C[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8] = A[1] + A[2] + A[3] + A[4] + A[5] +A[6] + A[7] + A[8];
2.那上述关系是怎么确定呢:
C[i] = A[n - 2^k + 1] + ...... + A[i];//n表示数组长度,k表示i的二进制时倒数第一个1后面的0的个数。如:10100倒数第一个1后面0的个数为2.
i为奇数时C[i] = A[i];
3.下面通过研究代码进一步理解怎么实现。
代码一:
int lowBit(int x) {
return x & (-x); //求的是2^k;
}
x表示C数状数组的下标。
代码二:
void modify(int pos, int num, int N) {//N表示数组长度,pos表示此时树状数组的下标。num表示放入树状数组的值。
初始时树状数组的值都为0。
while (pos <= N) {//从pos开始访问结点的父节点,并增加值 。
C[pos] += num;
pos += lowBit(pos);
}//traverse遍历
}
假设pos = 1;
此时C[1] += num;
由图二可知C[1]的父节点为C[2],即C[2] = C[pos += lowBit(pos)] = C[1 + lowBit(1)];
pos = 2;
此时C[2] += num;
由图二可知C[2]的父节点为C[4],即C[4] = C[pos += lowBit(pos)] = C[2 + lowBit(2)];
pos = 4;
此时C[4] += num;
.........
......
代码三:
int getSum(int pos) {//求1到pos的和
int sum = 0;
while (pos > 0) {
sum += C[pos];
pos -= lowBit(pos);
}
return sum;
}
假设pos = 12;
此时sum += C[12]
由图二可知pos减去lowBit(pos) = 4;后pos = 8;
pos = 8;
此时sum += C[8];
由图二可知pos减去lowBit(pos) = 8;后pos = 0;
所以此时跳出循环。
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 密码散列
- node公众号第三方模块,五分钟通过微信全网发布检测
- C#调用MySql数据库报错:KeyNotFoundException, 给定关键字不在字典中
- IDEA 调试技巧
- Android环境搭建
- 树状数组
- poj2689 素数距离(埃氏筛法分块筛+暴力枚举)
- HZDU 1008 Elevator
- 二叉树中的最大路径和
- zedboard qspi flash启动时,为什么program flash的加载速度很慢
- Android Studio中使用lambda表达式
- 图像特征提取
- C++/MFC-进程优先级
- 每天一个linux命令(50):crontab命令