问题链接:Problem J
问题简述:
敌人有N个工兵营地,给出每个营地的人数,接下来有四种命令:
(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 表示结束,这条命令在每组数据最后出现;
编写程序快速的处理四条命令。
问题分析:
对数列的单点更新与对区间和的询问。赤裸裸的线段树问题,照着模板套就好,要注意的是数据量较大,输入要用scanf而不能用cin不然容易TLE。(而且cin关闭同步后总是会出现一些奇怪的问题,我用cin提交会出现WA的情况,全部改成scanf就A了,很玄学,以后还是习惯用scanf吧)
程序说明:
使用了一个自行实现的堆栈,简单地实现逆序功能。本程序使用getchar()函数处理输入流,除了输入字符压栈外,读入的字符直接输出输出,没有使用多余的缓存。
AC通过的C++语言程序如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<cstring>
#include<cmath>
#define MAX 0x3f3f3f3f
using namespace std;
int tree[200005];
void pushup(int rt){
tree[rt]=tree[rt*2]+tree[rt*2+1];
}
void build(int l,int r,int rt){
if(l==r){
scanf("%d",&tree[rt]);
return;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
pushup(rt);
}
void update(int p,int num,int l,int r,int rt){
if(l==r){
tree[rt]+=num;
return;
}
else{
int mid=(l+r)/2;
if(p<=mid)
update(p,num,l,mid,rt*2);
else
update(p,num,mid+1,r,rt*2+1);
}
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt];
}
int mid=(l+r)/2;
int ans=0;
if(L<=mid)
ans+=query(L,R,l,mid,rt*2);
if(R>mid)
ans+=query(L,R,mid+1,r,rt*2+1);
return ans;
}
int main(){
int t;
scanf("%d",&t);
int cnt=0;
while(t--){
memset(tree,0,sizeof(tree));
cnt++;
printf("Case %d:\n",cnt);
int n;
scanf("%d",&n);
build(1,n,1);
char order[10];
while(scanf("%s",order)){
int a,b;
if(order[0]=='E')
break;
cin>>a>>b;
if(order[0]=='Q'){
cout<<query(a,b,1,n,1)<<endl;
}
else if(order[0]=='A'){
update(a,b,1,n,1);
}
else if(order[0]=='S'){
update(a,-b,1,n,1);
}
}
}
}