【解题报告】 NYOJ 116 士兵杀敌(二) 线段树 单点更新求区间和

这篇博客介绍了如何使用线段树进行单点更新和区间求和操作,针对NYOJ 116题目。作者指出线段树在处理此类更新和查询时具有高效的时间复杂度,是基础且重要的数据结构问题。
摘要由CSDN通过智能技术生成
题目连接: NYOJ 116

这个是线段树的基本操作----更新和查询,和上一个题一样,只不过一个是求最大值一个是求区间和,看来线段树在更新和查询的时候对时间的消耗很小很小。这个属于基础水题,我就不说什么了。

如果不知道线段树的基本操作,请移步 线段树的基本操作
// NYOJ 116 士兵杀敌(二) 线段树 --单点更新求区间和
// 
 
#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;

const int MAXNODE = 2097152; // == (1 << 21) - 1  depth:21
const int MAXS = 1000003;
struct SOILD{
	int left,right; // 数组模拟满二叉树, 区间 [left,right]
	int value;
}Soldier[MAXNODE];

int father[MAXS]; // 存每一个士兵的父结点

void BuildTree(int i,int left,int right,int devalue){ // 初始值为0
	Soldier[i].left = left;
	Soldier[i].right = right;
	Soldier[i].value = devalue;
	if (left == right){
		father[left] = i; // 可以瞬间知道第i个士兵的父节点是哪个
		return;
	}
	BuildTree(i*2, left, (int)floor((right+left)/2.0), 0);
	BuildTree(i*2+1, (int)floor((right+left)/2.0)+1, right, 0);
}

void UpdataTree(int ri,int iKilln){ // 单点更新: 点p[i,i] 更新为iKilln (初始为0)
	if (ri == 1){
		Soldier[ri].value += iKilln;
		return;
	}
	Soldier[ri].value += iKilln; // iKilln 设为全局变量应该快一点
	UpdataTree(ri/2,iKilln);
}

int res;
void Query(int i,int a,int b){ // [a,b]区间的和
	if (a == Soldier[i].left && b == Soldier[i].right){
		res += Soldier[i].value;
		return ;
	}
	if (a <= Soldier[i*2].right){ // 左端点小于右端点(几何含义:区间横跨过中点) 则区间需要分割
		if (b <= Soldier[i*2].right){
			Query(i*2, a, b); // 左边全包含
		}else{
			Query(i*2, a, Soldier[i*2].right); // 横跨取左
		}
	}
	if (b >= Soldier[i*2+1].left){
		if (a >= Soldier[i*2+1].left){
			Query(i*2+1, a, b); // 右边全包含
		}else{
			Query(i*2+1, Soldier[i*2+1].left, b); // 横跨取右
		}
	}
}

int main(){
	int n_s,n_q,iKilln,a,b;
	cin >> n_s >> n_q;
	BuildTree(1,1,n_s,0);
	for (int i = 1 ;i <= n_s; i++){ // 建树
		scanf("%d",&iKilln);	// iKilln 为第 i 个增加的杀敌数
		UpdataTree(father[i],iKilln); // 瞬间找到士兵的结点序号
	}
	char order[10];
	for (int i = 1; i <= n_q; i++){
		scanf("%s %d %d",&order[0],&a,&b); // [a,b] ; a + kill b 	
		if (order[0] == 'Q'){
			res = 0;
			Query(1,a,b);
			printf("%d\n", res);
		}else
			UpdataTree(father[a],b);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值