士兵杀敌(四)
时间限制: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
- 只有一组测试数据。
这个得用线段树。
先来看看从1到8的范围怎么搞。用二叉树把覆盖区间不断2分,直到为一点为止。
ADD数据 :1-8 +5;3-8 +3;5-6 +4;接着我们就只需把增加的值加到区间上;
注意:3-8是不能直接找到端点值匹配的区间的
接下来就是查询值,如果要查询第i个士兵的杀敌数,那么就从根开始一直沿着覆盖着 i 的区间到底,把经过的节点的值都加上就可以了;
比如查询6:
得到了12。这差不多能表示怎么利用树了吧 ~~~~~~ 0.0
#include<stdio.h>
int t=1048576;//t=2^20
int M;
int v[2300000]={0};
int m,n,add;
int p;
int temp;
void pback(int x,int a,int b)//表示的区域属于第m个士兵到第n个士兵之间的节点都加上ADD值
{
int mid=(a+b)/2;
if(m<=a&&b<=n)
{v[x]+=add;return;}
if(mid>=n)
{pback(x*2,a,mid);}
else if(mid<m)
{pback(x*2+1,mid+1,b);}
else
{
pback(x*2,a,mid);
pback(x*2+1,mid+1,b);
}
}
void Search(int x,int a,int b)//找第I个士兵的杀敌数值
{
int mid=(a+b)/2;
temp+=v[x];
if(a==b)
return;
if(mid>=p)
Search(x*2,a,mid);
else
Search(x*2+1,mid+1,b);
}
int main()
{
int T;
char s[10];
scanf("%d%d",&T,&M);
while(T--)
{
scanf("%s",s);
if(s[0]=='A')
{scanf("%d%d%d",&m,&n,&add);pback(1,1,t);}
if(s[0]=='Q')
{scanf("%d",&p);temp=0;Search(1,1,t);printf("%d\n",temp);}
}
return 0;
}