hduOJ 1166: 敌兵布阵

http://acm.hdu.edu.cn/showproblem.php?pid=1166


题目意思很明显,需要多次查询,多次进行修改操作。用线段树做,由于每次只对一个点进行修改,所以数据结构中只需要包含和项,而不必要包含修改标志。

代码如下:

/*
ID: csuchenan
PROG: hduoj 1166 敌兵布阵
LANG: C++
*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAXN 50005

struct Node{

	int left ;
	int right;
	int nsum ;
}node[3*MAXN + 5] ;

void build(int left , int right , int step) ;
void insert(int pos ,  int step , int nval) ;

//void update(int left , int right ,int nfalg);

void update(int pos , int nflag , int layer) ;

void query(int left , int right , int layer , int &nsum) ;

int n ;

int main(int argc , char * argv[]){

	int test ; 

	scanf("%d" , &test) ;
	int ncase ;
	ncase = 1 ;
	
	int i ;
	int j ;
	int data ;
	char str[10] ;
	int s ;
	int num  ;
	int nsum ;
	
	while(ncase <= test){
		
		printf("Case %d:\n" , ncase ++) ;
		
		scanf("%d" , &n) ;
		
		build(1 , n , 1) ;
		
		i = 1 ;
		
		while(i <= n){
			scanf("%d " , &data) ;
			insert(i , 1 , data) ;
			i ++ ;
		}
		
		while(1){
			scanf("%s" , str) ;
			
			if(strcmp(str , "End")==0){
				break ;
			}
			
			scanf("%d %d" , &s , &num) ;
			
			if(strcmp(str , "Query")==0){
				nsum = 0 ;
				
				query(s , num , 1 , nsum) ;
				
				printf("%d\n" , nsum) ;
				continue ;
			}
			
			if(strcmp(str , "Add") == 0){
				update(s , num , 1) ;
				continue ;
			}
			
			if(strcmp(str , "Sub") == 0){
				update(s , -num , 1) ;
				continue ;
			}
		}
	}
	
	return 0 ;
}

void build(int left , int right , int step){
	
	node[step].left = left ;
	node[step].right = right ;
	node[step].nsum = 0 ;
	

	if(left == right){
		return ;
	}	
	
	int mid = (left + right) / 2 ;
	
	int ls = step * 2 ;
	int rs = step * 2 + 1 ;

	build(left , mid , ls) ;
	build(mid + 1 , right , rs) ;
}

void insert(int pos , int step , int nval){

	//如果刚好区间相同,则直接插入,修改nsum的值
	if(node[step].left == pos && node[step].right == pos){
		
		node[step].nsum += nval ;
		return  ;
	}
	//否则,包含在该区间内,故而要将其的值累加到区间上,然后分左右区间
	
	node[step].nsum += nval ;
	
	int mid = (node[step].left + node[step].right) / 2 ;
	int nstep ;
	
	//分到左则
	
	if(pos <= mid){
			nstep = step * 2 ;
			insert(pos , nstep , nval) ;
			return  ;
	}
	
	//分到右侧
	nstep = step * 2 + 1 ;
	insert(pos , nstep , nval) ;
	
	return ;
}

void update(int pos , int nflag , int layer){
	
	if(node[layer].left == pos && node[layer].right == pos){
		node[layer].nsum += nflag ;
		return ;
	}
	
	//对于该区间上的值直接进行累加
	node[layer].nsum += nflag ;
	
	int mid = (node[layer].left + node[layer].right) / 2 ;
	
	int nlayer  ;
	
	//分到左侧
	if(pos <= mid){
		
		nlayer = layer * 2 ;
		update(pos , nflag , nlayer) ;
		return ;
	}
	//右侧
	nlayer = layer * 2 + 1 ;
	update(pos , nflag , nlayer) ;
	
	return ;
}

void query(int left , int right , int layer , int &nsum){
	
	if(node[layer].left == left && node[layer].right == right){
		
		nsum += node[layer].nsum ;
		return ;
	}

	int mid = (node[layer].left + node[layer].right) / 2 ;
	
	int nlayer ;
	
	if(right <= mid){
	
		nlayer = layer * 2 ;
		query(left , right , nlayer , nsum) ;
		return ;
	}
	
	if(left > mid){
	
		nlayer = layer * 2 + 1 ;
		query(left , right , nlayer , nsum) ;
		return ;
	}
	
	nlayer = layer * 2 ;
	
	query(left , mid , nlayer , nsum) ;
	
	nlayer ++ ;
	
	query(mid + 1 , right , nlayer , nsum) ;
	
	return ;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值