【ssl2648】线段树练习题5【线段树变式】

Description

一行N个方格,开始每个格子里的数都是0。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N≤100000,提问和修改的总数可能达到100000条。

Input

20 //方格个数 
6 //有几组操作 
M 1 1 //表示修改,第一个表示格子位置,第二个数表示在原来的基础上加上的数, 
M 2 2 
M 3 4 
M 3 -5 
M 6 7 
C 2 6 //表示统计 ,第一个数表示起始位置,第二个数表示结束位置

Output

8

分析

这题就是线段树上的单点修改, 但是修改的时候要继续往下修改直道叶子节点。
每次统计的时候是一个区间,所以就需要二分,看看区间是全部在左边,还是全部在右边,还是两边都有,就继续往下递归,直到当前区间与要查找的区间重合或者到了叶子节点。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,tree[300001],x,y;//数组要开大一点!!要300000! 
char ff;
void insert(int k,int l,int r)//[l,r]表示当前需要插入的区间,k表示树上节点编号 
{
	int mid=(l+r)/2;
	if(l==r)//已经是单位区间 
	{
		tree[k]+=y;//对这个点修改 
		return;
	}
	if(x<=mid) insert(k*2,l,mid);
	else if(x>mid) insert(k*2+1,mid+1,r);
	tree[k]+=y;
} 
int cnt(int k,int l,int r,int x,int y)
{
	if(r>n) return 0;//没有区间 
	if(x==l&&y==r) return tree[k];//要查找的区间和所在区间一样,直接返回
	int mid=(l+r)/2;
	if(y<=mid) return cnt(k*2,l,mid,x,y);
	else if(x>mid) return cnt(k*2+1,mid+1,r,x,y);
	else
	{
		return cnt(k*2,l,mid,x,mid)+cnt(k*2+1,mid+1,r,mid+1,y);
		/*因为两边都有,所以加起来,并且查找范围也发生了变化,
		可以刚好覆盖[x,y]的范围(把[x,y]分成[x,mid]和[mid+1,y])*/ 
	} 
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		cin>>ff;
		scanf("%d%d",&x,&y);
		if(ff=='M') insert(1,1,n);
		else if(ff=='C') cout<<cnt(1,1,n,x,y)<<endl;//其实区间[x,y]内在统计函数里有一个累加的数值 
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值