士兵杀敌(二)
- 描写叙述
-
南将军手下有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
-
士兵杀敌(一) 数组是固定的,所以能够用一个sum数组来保存每一个元素的和即可,可是不能每次都加,由于那样会超时。查询次数太多。可是这个士兵杀敌(二)就不能用那个方法来解了,由于这个是动态的,中间元素的值可能会变化。所以引出一个新的东西来。刚開始想了一下,实在是没有想到方法,就去讨论区看了看,一看好像都说用树状数组,就去找树状数组的使用方法。
先上图。看着图解释easy理解点。
数组A是原数组中的元素。数组C是树状数组中的元素,图中C数组的元素组成为A中的某些元素之和,这些元素的个数取决于它的下标能被多少个2整除,像C[1] = A[1]; C[2] = A[1] + A[2]; C[3] = A[3]; C[4] = A[1] + A[2] + A[3] + [4] = C[2] + C[3]; ……这些个数能够写一个通式C[i] = A[n - 2^k + 1] + ……+A[i]; 当中k为 i 的二进制中从右往左数的 0 的个数 ,就像6有一个, 6能够写成 2 × 3, 所以C[6] = A[5] + A[6]; 所以能够定义一个函数来求这个数.
6的二进制为0110
5的二进制为0101
6^5 = 0011
6&(6^5) = 0010 = 十进制中的2
所以函数能够这么写
int lowbit(int N)//求n中有多少个能被2的多少次幂整除的。即2^k, 也就是树状数组的作用域 { return N & (N ^ (N - 1)); }
也能够写成
int lowbit(int N)//求n中有多少个能被2的多少次幂整除的,即2^k, 也就是树状数组的作用域 { return N & (-N); }
更改一个数的值, 就要更改次数在树状数组中的全部祖先,只是这个时间复杂度是O(logn); 以下是更改值(加入杀敌数)的函数
void add(int pos, int num)//加入新值到树状数组中 { while(pos <= n) { tmp[pos] += num; pos += lowbit(pos); } }
以下就是求和函数。 由于这样的方法之所以快。是求他的最小树根节点的和, 最小树的个数为当前要求的n的二进制中为1的个数。即展开式中能写成不同2的幂指数的项数。
比如: 15 = 2^3 + 2^2 + 2^1 + 2^0; 所以n = 15时, 最小数有四个。求和的时间复杂度为O(logn);
int Sum(int N)//求前N个数的和 { int sum = 0; while(N > 0) { sum += tmp[N]; N -= lowbit(N); } return sum; }
关键就是这三步, 这三步搞明确了,基本上就不成问题了。可是。当时依照 杀敌(一) 中的思维。还统计了一个总数,那样不会快,反而会慢,所以直接求即可。以下是完整的代码
-
#include<stdio.h> #include<string.h> int a[1000010]; int n,m; int lowbit(int N)//求n中有多少个能被2的多少次幂整除的。即2^k, 也就是树状数组的作用域 { return N&(-N); } void asd(int i,int M)//加入新值到树状数组中 { while(i<=n) { a[i]+=M; i+=lowbit(i); } } int sum(int N)//求前N个数的和 { int sum=0; while(N>0) { sum+=a[N]; N-=lowbit(N); } return sum; } int main() { int i,t,a,b; char str[10]; scanf("%d %d",&n,&m); for(i=1;i<=n;i++) { scanf("%d",&t); asd(i,t); } while(m--) { scanf("%s %d %d",str,&a,&b); if(!strcmp(str,"QUERY")) printf("%d ",sum(b)-sum(a-1)); else asd(a,b); } return 0; }
版权声明:本文博主原创文章,博客,未经同意不得转载。