看了一些博客终于知道线段树是啥了,然后拿水题试试水。
线段树其实是一种特殊的二叉树,每个结点相当于一个个区间,包含了左边界和右边界以及这些区间的和。根据题意可知道需要对数据进行3000次的查询、添加、消减处理所以必须用线段树这种数据结构。不然一定会超时。
本来测试用例过了,但还是超时了,十分不解,最后看一个老兄的题解才知道要把cin换成scanf =_=
orz
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = (5e4 + 1) * 4; // 线段树的结点至少是叶子的四倍
int cnt;
struct node {
int l; //区间左端
int r; //区间右端
int sum; //这段区间的和
};
node tree[maxn];
void build(int l, int r, int k) {
tree[k].l = l;
tree[k].r = r;
if (l == r) {
scanf("%d", &tree[k].sum);
return;
}
int m = (l + r) / 2;
build(l, m, k * 2); //左孩子
build(m + 1, r, k * 2 + 1); //右孩子
tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum; //状态合并,此结点的sum为两个孩子的sum之和。
}
void add(int i, int j, int k) {
if (tree[k].l == tree[k].r) {
tree[k].sum += j;
return ;
}
int m = (tree[k].l + tree[k].r) / 2;
if (i <= m) add(i, j, k * 2);
else add(i, j, k * 2 + 1);
tree[k].sum = tree[k * 2].sum + tree[k * 2 + 1].sum;
}
void query(int i, int j, int k) {
if (tree[k].l == i && tree[k].r == j) {
cnt += tree[k].sum;
return ;
}
int m = (tree[k].l + tree[k].r) / 2;
if (j <= m) query(i, j, k * 2);
else if (i > m) query(i, j, k * 2 + 1);
else {
query(i, m, 2 * k);
query(m + 1, j, 2 * k + 1);
}
}
int main() {
//freopen("input.txt", "r", stdin);
int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++) {
printf("Case %d:\n", kase);
int n;
scanf("%d", &n);
getchar();
build(1, n, 1); //建树
getchar();
char op[10];
while(scanf("%s", op)) {
cnt = 0;
if (op[0] == 'E') break; //结束
int i, j;
scanf("%d%d", &i, &j);
switch (op[0]) {
case 'Q': query(i, j, 1); printf("%d\n", cnt); break;
case 'A': add(i, j, 1); break;
case 'S': add(i, -j, 1); break;
}
}
}
return 0;
}