现在的位置: 首页 > 综合 > 正文

[poj 1166]敌兵布阵[线段树基础]

2018年03月17日 ⁄ 综合 ⁄ 共 1217字 ⁄ 字号 评论关闭
#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;
}

抱歉!评论已关闭.