第八次训练 J题

问题链接: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);
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值