首页 > 代码库 > 士兵杀敌(二)
士兵杀敌(二)
题目来源(数据结构类型:树状数组)
士兵杀敌(二)
时间限制: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
对于很小的n用一般的for循环可以求和或变更内容后求和得出题目的答案,可是对于很大的n来说,程序会因为多次循环而变的很慢(时间就是金钱啊,有木有),所以我们要想法优化数据的存储结构,一个好的数据结构带来的肯定是时间上的减缩,何乐而不为.废话不多说,本题使用树状数组来存储题目数据。首先看图片(来自百度)认识一下树状数组:
我们称数组c为树状数组,它的特点是,c[i]存储的是A[i-2^k + 1]到A[i]的和(和士兵杀敌(一)的数组有的类似,这里的数组c[i]存储的是某一个区间的和),需要说明的是:k为i在二进制形式下有效0的个数(一般用 i & (-i) 直接求出 2^k的值).
那么问题来了.....
1. 如何求出前 i 项的和(求前 i 项和为了的到某一区间的和,这个思想用于士兵杀敌(一)中)。
2. 若数组A[]的某一个元素更新,如何更新数组c[]的值。
对于这两个问题请参考:http://www.java3z.com/cwbwebhome/article/article19/zip/treearray.zip实在不是太懂,汗颜啊!
下面给出代码:
#include<stdio.h> #define MAX 1000000 int ans[MAX+1]; /*直接计算2^k的值*/ int lowbit(int x) { return x&(-x); } /*更新数组位置 i 的值*/ void update(int i,int n,int N) { while(i<=N){ //printf("i = %d\n",i); ans[i]+=n; i+=lowbit(i); } } /*求出前 i 项的和*/ int sum(int n) { int s=0; while(n>0){ s+=ans[n]; n-=lowbit(n); } return s; } int main() { int N,M; int i,t,p,q; char ch[6]; scanf("%d%d",&N,&M); for(i=1;i<=N;i++){ scanf("%d",&t); update(i,t,N); } for(i=1;i<=M;i++){ scanf("%s %d %d",ch,&p,&q); if(ch[0]=='Q') printf("%d\n",sum(q)-sum(p-1)); else update(p,q,N); } return 0; }
士兵杀敌(二)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。