hdu 1166(线段树模板题)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
题意:
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令

思路:
题目有多个营地,要求修改一个营地的人数,查询多个营地的总人数
单点修改,区间查询,可以使用线段树

实现:
叶子节点存储单个营地人数,负责修改,父节点存储多个营地的总人数,负责查询。
结构体数组存储节点,需要开营地数量*3的空间才足够存储数据。

#include
#include
#define N 50005
int value[N];
struct node{
	int l,r,sumn;
}tree[50000*3];
int Build(int root,int l,int r){
	tree[root].l = l;
	//左边界和右边界的值,代表节点包含的营地数量
	tree[root].r = r;
	if(l == r){
		//叶子节点,没有子节点,存储单个营地人数
		return tree[root].sumn = value[l];
	}
	int mid = (l+r) >> 1;
	int a,b;
	a = Build(root<<1,l,mid);
	//往下建立左子树和右子树
	b = Build(root<<1|1,mid+1,r);
	//得到节点的值,从子节点往上,确定各个营地区间的总人数
	return tree[root].sumn = a+b;
}
int query(int root,int l,int r){
	int ans = 0;
	int tl = tree[root].l, tr = tree[root].r;
	if(tl > r || tr < l){
	//节点不在查询区间内,返回0
		return 0;
	}
	if(tr <= r && tl >= l){
		//节点完全包括在查询区间中,返回营地总人数
		ans = tree[root].sumn;
		return ans;
	}
	int a,b;
	//节点只有部分包括在查询区间中
	//往子节点查询,一直到子节点完全包括在查询区间中为止
	a = query(root<<1,l,r);
	b = query(root<<1|1,l,r);
	ans = a+b;
	return ans; 
	
}

int add(int root,int index,int num){
	
	int tl = tree[root].l, tr = tree[root].r;
	if(tl > index || tr < index){
		//节点的子节点中不包含要修改人数的营地
		//不再找子节点,返回原值
		return tree[root].sumn; 
	}
	if(tl == tr){
		if(tl == index){
			//对营地人数进行修改
			tree[root].sumn+=num;
		}
		return tree[root].sumn;
	}
	int a,b;
	a = add(root<<1,index,num);
	b = add(root<<1|1,index,num);
	//根据被修改的叶子节点(单个营地人数)
	//改变父节点的值(多个营地的总人数)
	return tree[root].sumn = a+b;
}

int main(){
	int t;
	scanf("%d",&t);
	for(int t1 = 1;t1 <= t ;t1++){
		int n;
		scanf("%d",&n);
		for(int i = 1;i <= n;i++){
			scanf("%d",&value[i]);
		}
		Build(1,1,n);//通过数据建线段树
		char com[10];
		
		printf("Case %d:\n",t1);
		while(scanf("%s",com)){
			if(!strcmp(com,"End")){
				break;	
			}
			int i,j;
			scanf("%d%d",&i,&j);
			getchar();
			if(!strcmp(com,"Query")){
				printf("%d\n",query(1,i,j));
			}else if(!strcmp(com,"Add")){
				add(1,i,j);
			}else if(!strcmp(com,"Sub")){
				add(1,i,-j);
			} 
		}
	}
}

你可能感兴趣的:(hdu 1166(线段树模板题))