NY116

来源:互联网 发布:那个基金软件好 编辑:程序博客网 时间:2024/06/06 19:13


士兵杀敌(二)

时间限制: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 61 2 3 4 5QUERY 1 3ADD 1 2QUERY 1 3ADD 2 3QUERY 1 2QUERY 1 5
样例输出
68820

树状数组:

 #include <stdio.h>#include <string.h>int tmp[1001000];int n, k;int lowbit(int N)//求n中有多少个能被2的多少次幂整除的,即2^k, 也就是树状数组的作用域{    return N & (-N);}void add(int pos, int num)//添加新值到树状数组中{    while(pos <= n)    {        tmp[pos] += num;        pos += lowbit(pos);    }}int Sum(int N)//求前N个数的和{    int sum = 0;    while(N > 0)    {        sum += tmp[N];        N -= lowbit(N);    }    return sum;}int main(){    int a, b, temp;    char str[10];    scanf("%d %d", &n, &k);    for(int i = 1; i <= n; i++)    {        scanf("%d", &temp);        add(i, temp);    }    for(int i = 0; i < k; i++)    {        scanf("%s %d %d", str, &a, &b);        if(strcmp(str, "QUERY") == 0)            printf("%d\n", Sum(b) - Sum(a - 1));        else            add(a, b);    }    return 0;}        

暑假第五次测试:

问题 B: 敌兵布阵

时间限制: 1 Sec  内存限制: 32 MB
提交: 60  解决: 31
[提交][状态][讨论版]

题目描述

C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.

输入

第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令。

输出

对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。

样例输入

1101 2 3 4 5 6 7 8 9 10Query 1 3Add 3 6Query 2 7Sub 10 2Add 6 3Query 3 10End 

样例输出

Case 1:63359

//树状数组求解,不懂的看下面链接,直接套模板就行 //http://blog.csdn.net/int64ago/article/details/7429868#include<stdio.h>#include<string.h>int N, tree[50010];//构建数 void add(int k, int num){ //k为结点标号,Num为当前结点新加的个数 while(k <= N){tree[k] += num;k += k&-k;   //博客里有详解 }}void sub(int k, int num){ //k为结点标号,Num为当前结点新加的个数 while(k <= N){tree[k] -= num;k += k&-k;   //}}int read(int k){   //求区间1~K的和 int sum = 0;while(k){sum += tree[k];k -= k&-k;}return sum;}int main(){int m, n, ans, x, t;int kase = 1, flag; char str[7];scanf("%d", &t);while(t--){memset(tree, 0, sizeof(tree));flag = 1;scanf("%d", &N);for(int i = 1; i <= N; i++){scanf("%d", &x);add(i, x);}while(scanf("%s", str) != EOF){if(str[0] == 'Q'){scanf("%d%d", &m, &n);ans = read(n)-read(m-1);if(flag){printf("Case %d:\n", kase++);flag = 0;}printf("%d\n", ans);}else if(str[0] == 'A'){scanf("%d%d", &m, &n);add(m, n);}else if(str[0] == 'S'){scanf("%d%d", &m, &n);sub(m, n);}else if(str[0] == 'E')break;}}return 0;}//线段树求解 #include<stdio.h>#include<string.h>int tree[50010*4];//递归建立线段树  void build(int left, int right, int root){if(left == right){scanf("%d", &tree[root]);return;}int mid = (left+right)/2;build(left, mid, root*2);build(mid+1, right, root*2+1);tree[root] = tree[root*2]+tree[root*2+1]; //收集子节点的结果  }//update这个函数就有点定制的意味了  //本题是单点更新,所以是在区间[left,right]内使得第id数的值+add  //如果是区间更新,可以update的参数需要将id变为L和R  void update(int p, int add, int left, int right, int root){int mid = (left+right)/2;if(left == right){tree[root] += add;return;}if(p <= mid)update(p, add, left, mid, root*2);elseupdate(p, add, mid+1, right, root*2+1);tree[root] = tree[root*2]+tree[root*2+1];//时刻记住维护i节点统计信息正确性  }//在当前区间[left, right]内查询区间[L, R]间的目标值  //且能执行这个函数的前提是:[left,right]与[L,R]的交集非空  //其实本函数返回的结果也是 它们交集的目标值  int query(int L, int R, int left, int right, int root){int mid = (left+right)/2;int ans = 0;if(L <= left && right <= R){return tree[root];}if(mid >= L) ans += query(L, R, left, mid, root*2);if(mid+1 <= R)  ans += query(L, R, mid+1, right, root*2+1);return ans;}int main(){int t, n, a, b;int kase = 1;scanf("%d", &t);while(t--){scanf("%d", &n);build(1, n, 1);char str[10];printf("Case %d:\n", kase++);while(scanf("%s", str) != EOF){if(str[0] == 'E') break;scanf("%d%d", &a, &b);if(str[0] == 'A')update(a, b, 1, n, 1);else if(str[0] == 'S')update(a, -b, 1, n, 1);elseprintf("%d\n", query(a, b, 1, n, 1));}}return 0;}

树状数组参考博客:http://www.cnblogs.com/GeniusYang/p/5756975.html

http://www.cnblogs.com/circlegg/p/7189676.html

http://blog.csdn.net/int64ago/article/details/7429868


百度百科:https://baike.baidu.com/item/树状数组/313739?fr=aladdin