题意:给n个兵营的人数,有操作:
Add i j: 给第i个兵营加j人
Sub i j: 第i个兵营减j人
Query i j: 查询第i个到第j个(区间[i,j])的总人数
End: 退出操作.
首先注意到Add和Sub是一样的,Sub i j我们可以用操作Add i -j等价替换掉。于是有两种操作:单点修改,区间查询。因此可以用树状数组简单实现。自然也可以用线段树。
树状数组实现:
#include <cstdio>
#include <cstring>
const int MAX = 50050;
int s[MAX];
int lb(int x) {
return x&(-x);
}
/* œÚµãxÔöŒÓval */
void update(int x, int val) {
while (x <= MAX) {
s[x] += val;
x += lb(x);
}
}
int query(int x) {
int sum = 0;
while (x > 0) {
sum += s[x];
x -= lb(x);
}
return sum;
}
int main() {
char op[10];
int T, n, a, b;
register int i;
scanf(" %d", &T);
while (T--) {
scanf(" %d", &n);
memset(s, 0, sizeof(s));
for (i = 1; i <= n; ++i) {
scanf(" %d", &a);
update(i, a);
}
static int cas = 0;
printf("Case %d:\n", ++cas);
while (~scanf(" %s", op) && strcmp(op, "End")) {
scanf(" %d %d", &a, &b);
if (strcmp(op, "Query") == 0)
printf("%d\n", query(b)-query(a-1));
else if (strcmp(op, "Add") == 0)
update(a, b);
else
update(a, -b);
}
}
return 0;
}
线段树:
//所有区间表示a~b都为[a,b],闭区间
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAX = 50007;
int po[MAX];
struct node {
int sum; //区间总人数
} a[MAX << 2];
inline int L(const int& root) {
return root << 1;
}
inline int R(const int& root) {
return root << 1 | 1;
}
void build(int root, int left, int right) {
if (left > right) {
return;
} else if (left == right) {
a[root].sum = po[left];
} else {
int mid = (left + right) >> 1;
build(L(root), left, mid);
build(R(root), mid + 1, right);
a[root].sum = a[L(root)].sum + a[R(root)].sum;
}
}
//给pos加num,num<0时相当于减
void modify(int root, int left, int right, int pos, int num) {
if (pos == left && pos == right) {
a[root].sum += num;
} else if (pos < left || pos > right) {
return;
} else {
int mid = (left + right) >> 1;
modify(L(root), left, mid, pos, num);
modify(R(root), mid + 1, right, pos, num);
a[root].sum = a[L(root)].sum + a[R(root)].sum;
}
}
int query(int root, int left, int right, int s, int e) {
if (s <= left && e >= right) {
return a[root].sum;
} else if (e < left || s > right) {
return 0;
} else {
int mid = (left + right) >> 1;
return query(L(root), left, mid, s, e) + query(R(root), mid + 1, right, s, e);
}
}
inline int read() {
char ch;
while ((ch = getchar()) < '0' || ch > '9');
int x = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
}
return x;
}
int main() {
int T = read();
//scanf(" %d", &T);
while (T--) {
int N = read();
//scanf(" %d", &N);
for (int i = 1; i <= N; ++i) {
po[i] = read();
//scanf(" %d", po + i);
}
build(1, 1, N);
char s[20];
int left, right;
static int __ = 0;
printf("Case %d:\n", ++__);
while (~scanf(" %s", s) && s[0] != 'E') {
left = read();
right = read();
//scanf(" %d %d", &left, &right);
switch(s[0]) {
case 'A':
modify(1, 1, N, left, right);
break;
case 'S':
modify(1, 1, N, left, -right);
break;
case 'Q':
printf("%d\n", query(1, 1, N, left, right));
break;
default:
break;
}
}
}
return 0;
}