#include <cstdio>
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 55555;
int sum[maxn<<2];//x4
void PushUP(int rt) {//区间求和,从叶子节点更新上来
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void build(int l,int r,int rt) {
if (l == r) {//线段树是基于数组的,节点一层一层排下来,完全二叉树
scanf("%d",&sum[rt]);
return ;
}//从父节点出发,左儿子和右儿子是通过数组下标找到的
//而其对应的左端点和右端点是在参数传递的时候同步保存的,不需特别记录
int m = (l + r) >> 1;//middle
build(lson);//define的作用!
build(rson);//总是先调用左儿子,保证叶子节点的建立顺序是从小到大
PushUP(rt);
}
void update(int p,int add,int l,int r,int rt) {//更新也是递归的
if (l == r) {//如果两儿子是叶子节点
sum[rt] += add;
return ;
}//如果两儿子不是叶子节点,更新两儿子
int m = (l + r) >> 1;
if (p <= m) update(p , add , lson);
else update(p , add , rson);
PushUP(rt);//更新自己
} //询问区间 扫描区间 子树根节点/当前节点
int query(int L,int R,int l,int r,int rt) {//询问也是递归的
if (L <= l && r <= R) {//一个节点的特征参数即左右端点和数组下标
return sum[rt];
}//如果该节点的管辖区域全在查询区域内,直接返回该节点数据
int m = (l + r) >> 1;
int ret = 0;//看所询问区间是否涉及左 or 右儿子;涉及,则递归询问
if (L <= m) ret += query(L , R , lson);//总能抵达L==l||r==R
if (R >= m+1) ret += query(L , R , rson);
return ret;
}
int main() {
int T , n;
scanf("%d",&T);
for (int cas = 1 ; cas <= T ; cas ++) {
printf("Case %d:\n",cas);
scanf("%d",&n);
build(1 , n , 1);//sum数组从1开始
char op[10];
while (scanf("%s",op)) {//以空格为分隔符
if (op[0] == 'E') break;
int a , b;
scanf("%d%d",&a,&b);
if (op[0] == 'Q') printf("%d\n",query(a , b , 1 , n , 1));
else if (op[0] == 'S') update(a , -b , 1 , n , 1);
else update(a , b , 1 , n , 1);
}
}
return 0;
}
[poj 1166]敌兵布阵[线段树基础]
最新推荐文章于 2019-05-27 13:46:09 发布