题面
【题目描述】
有
n
n
n个营地,已知每个营地的人数,有四条命令:
(
1
)
A
d
d
(1) Add
(1)Add
i
i
i
j
j
j,
i
i
i和
j
j
j为正整数,表示第
i
i
i个营地增加
j
j
j个人(
j
j
j不超过
30
30
30)
(
2
)
S
u
b
(2)Sub
(2)Sub
i
i
i
j
j
j ,
i
i
i和
j
j
j为正整数,表示第
i
i
i个营地减少
j
j
j个人(
j
j
j不超过
30
30
30);
(
3
)
Q
u
e
r
y
(3)Query
(3)Query
i
i
i
j
j
j ,
i
i
i和
j
j
j为正整数,
i
≤
j
i\leq j
i≤j,表示询问第
i
i
i到第
j
j
j个营地的总人数;
(
4
)
E
n
d
(4)End
(4)End 表示结束,这条命令在每组数据最后出现;
【输入格式】
第一行一个整数
T
T
T,表示有
T
T
T组数据。
每组数据第一行一个正整数N(
N
≤
50000
N \leq 50000
N≤50000),表示敌人有N个工兵营地,接下来有
N
N
N个正整数,第
i
i
i个正整数
a
i
a_i
ai代表第
i
i
i个工兵营地里开始时有
a
i
a_i
ai个人(
1
≤
a
i
≤
50
1 \leq a_i \leq 50
1≤ai≤50)。
接下来每行有一条命令,最多
40000
40000
40000条。
【输出】
对第i组数据,首先输出“
C
a
s
e
Case
Case
i
:
i:
i:”和回车,
对于每个
Q
u
e
r
y
Query
Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在
i
n
t
int
int以内。
【样例输入】
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
【样例输出】
Case 1:
6
33
59
算法分析
线段树模板题目。
单点修改,区间查询。
参考程序
#include<bits/stdc++.h>
#define N 50010
using namespace std;
int T,n,a[N],s[4*N]; //4倍n
void built(int k,int l,int r) //建线段树
{
if(l==r) {s[k]=a[l];return;}
int mid=(l+r)/2;
built(2*k,l,mid);
built(2*k+1,mid+1,r);
s[k]=s[k*2]+s[k*2+1];
}
void update(int k,int l,int r,int x,int v) //单点更新
{
if(l==r&&l==x){s[k]+=v;return;} //找到单点修改
if(x<l||x>r) return;
int mid=(l+r)/2;
if(l<=x&&x<=mid) update(k*2,l,mid,x,v);
if(mid+1<=x&&x<=r) update(k*2+1,mid+1,r,x,v);
s[k]=s[k*2]+s[k*2+1]; //回溯,维护区间和
}
int ask(int k,int l,int r,int x,int y) //区间查询
{
if(y<l||x>r) return 0; //不相交
if(x<=l&&r<=y) return s[k]; //包含
int mid=(l+r)/2;
return ask(k*2,l,mid,x,y)+ask(k*2+1,mid+1,r,x,y);
}
int main(){
scanf("%d",&T);
int count=1;
while(count<=T)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
built(1,1,n);
char s[10];
int x,y;
printf("Case %d:\n",count);
while(1)
{
scanf("%s",s);
if(s[0]=='E') break;
scanf("%d%d",&x,&y);
if(s[0]=='A') update(1,1,n,x,y);
if(s[0]=='S') update(1,1,n,x,-y);
if(s[0]=='Q') printf("%d\n",ask(1,1,n,x,y));
}
count++;
}
return 0;
}