现在的位置: 首页 > 综合 > 正文

NYOJ-123 士兵杀敌(四)树状数组 插线问点

2017年11月10日 ⁄ 综合 ⁄ 共 1435字 ⁄ 字号 评论关闭

士兵杀敌(四)

时间限制:2000 ms  |  内存限制:65535 KB
难度:5
描述

南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧。

假设起始时所有人的军功都是0.

输入
只有一组测试数据。
每一行是两个整数T和M表示共有T条指令,M个士兵。(1<=T,M<=1000000)
随后的T行,每行是一个指令。
指令分为两种:
一种形如
ADD 100 500 55 表示,第100个人到第500个人请战,最终每人平均获得了55军功,每次每人获得的军功数不会超过100,不会低于-100。
第二种形如:
QUERY 300 表示南将军在询问第300个人的军功是多少。
输出
对于每次查询输出此人的军功,每个查询的输出占一行。
样例输入
4 10
ADD 1 3 10
QUERY 3
ADD 2 6 50
QUERY 3
样例输出
10
60

这题用树状数组来做,是叫插线问点吧,已经有很多博文写了,代码很简单,可是都只有代码,这里我就说说我自己的理解吧。

当要给从from到to的士兵加军功e的时候,就给(1,from-1)的士兵加-e的军功,给(1,to)的士兵加军功。(Add函数)

根据树状数组的特性,当给某段士兵加军功时,数组中不是每个士兵的军功值都会变化,比如下图(图来自百度百科)中,当从4开始减少e1军功时,1,2,3中是不变的,只有4减少了e1,当从8开始-e2时,1到7都不变,只有8减少了e2,增加军功e3是相同的道理,所以当要查询3时,所以要对其父节点4、8……求和。(GetSum函数)

总结起来就是

1 父节点的变化反映了其下子节点的变化

2 子节点的值由其不同维度的父节点决定(4是3的父节点,8也是3父节点,16也是3的父节点……)

具体代码如下(都大同小异):

#include
<cstdio>
02.using namespace std;
03. 
04.#define
MAXN 1000010
05.int me[MAXN],M;
06. 
07.void Add(int x,int val)
08.{
09.while(x)
10.{
11.me[x]+=val;
12.x-=x&(-x);
13.}
14.}
15. 
16.int GetSum(int x)
17.{
18.int sum=0;
19.while(x<=M)
20.{
21.sum+=me[x];
22.x+=x&(-x);
23.}
24.return sum;
25.}
26. 
27.int main()
28.{
29.char command[6];
30.int T,from,to,e;
31.scanf("%d%d",&T,&M);
32.while(T--)
33.{
34.scanf("%s",command);
35.if(command[0]=='A')
36.{
37.scanf("%d%d%d",&from,&to,&e);
38.Add(from-1,-e);
39.Add(to,e);
40.}
41.else
42.{
43.scanf("%d",&from);
44.printf("%d\n",GetSum(from));
45.}
46.}
47.return 0;
48.}

抱歉!评论已关闭.