- 题目123
- 题目信息
- 运行结果
- 本题排行
- 讨论区
士兵杀敌(四)
2000 ms | 内存限制: 65535
南将军麾下有百万精兵,现已知共有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.在区间更新数据的时候 只要找到区间即可 无需找到具体的位置
2.查询的时候要一搜到底。
这道题对比着士兵杀敌(二)区间查询单点更新 还是很容易理解的
代码:
#include <stdio.h>
struct node
{
int left,right;
long long num;
}tree[1000000*4];
//初始化线段树
void build(int left,int right,int root)
{
tree[root].left=left;
tree[root].right=right;
if(left==right)
{
tree[root].num=0;
return ;
}
else
{
int mid=(left+right)>>1;
build(left,mid,root*2);
build(mid+1,right,root*2+1);
tree[root].num=0;
}
}
//更新区间值
void update(int l,int r,int x,int root)
{
//找到对应区间即可
if(tree[root].left==l&&tree[root].right==r)
{
tree[root].num+=x;
return ;
}
int mid=(tree[root].left+tree[root].right)>>1;
if(mid<l)
update(l,r,x,root*2+1);
else if(mid>=r)
update(l,r,x,root*2);
else
{
update(l,mid,x,root*2);
update(mid+1,r,x,root*2+1);
}
}
//从根到叶子 一搜到底
void search(int root,int pos,long long &result)
{
if(tree[root].left==tree[root].right&&tree[root].left==pos)
{
result+=tree[root].num;
return ;
}
int mid=(tree[root].left+tree[root].right)>>1;
if(pos>mid)
search(root*2+1,pos,result);
else
search(root*2,pos,result);
result+=tree[root].num;
}
int main()
{
int n,k;
scanf("%d %d",&k,&n);
build(1,n,1);
for(int i=0;i<k;i++)
{
char str[20];
scanf("%s",str);
if(str[0]=='A')
{
int a,b,x;
scanf("%d %d %d",&a,&b,&x);
update(a,b,x,1);
}
if(str[0]=='Q')
{
int pos;
long long result=0;
scanf("%d",&pos);
search(1,pos,result);
printf("%d\n",result);
}
}
return 0;
}