【线段树】线段树练习题五

Description

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

Input

第一行, n n n,为方格个数
第二行, m m m,为操作数
3 3 3 m + 2 m+2 m+2
每行第一个字符, M M M C C C
如果是 M M M,后面有 l l l, k k k
为在 l l l点加 k k k
如果是 C C C,后面有 l l l, r r r
为输出 l l l, r r r之间数的和

Output

若干行
每行一个数
l i l_i li, r i r_i ri之间数的和

Sample Input
 20
6
M 1 1
M 2 2
M 3 4
M 3 -5
M 6 7
C 2 6
Sample Output
8

思路

线段树

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
struct tree_1
{
	ll l,r,k,store;
}Tree[400250];
int A[100250];
int Operation,Sum;
int n,m,k;
//--------------------------------------------------------------
void Go(int Hi,int Len)
{
	if(!Tree[Hi].store)return;
	Tree[Hi*2].store+=Tree[Hi].store;
	Tree[Hi*2+1].store+=Tree[Hi].store;
	Tree[Hi*2].k+=Tree[Hi].store*(Len-Len/2);
	Tree[Hi*2+1].k+=Tree[Hi].store*(Len/2);
	Tree[Hi].store=0;
}
void Tree_Buil(int Hi,int l,int r)
{
	Tree[Hi].l=l;Tree[Hi].r=r;
	if(l==r)Tree[Hi].k=A[l];
	else
	{
		int Mid=(l+r)/2;
		Tree_Buil(Hi*2,l,Mid);
		Tree_Buil(Hi*2+1,Mid+1,r);
		Tree[Hi].k=Tree[Hi*2].k+Tree[Hi*2+1].k;
	}
	return;
}
//--------------------------------------------------------------
void Add(int Hi,int l,int r,int k)
{
	if(Tree[Hi].l==l && Tree[Hi].r==r)
	{
		Tree[Hi].k+=(r-l+1)*k;
		Tree[Hi].store+=k;
		return;
	}
	if(Tree[Hi].l==Tree[Hi].r)return;
	Go(Hi,Tree[Hi].r-Tree[Hi].l+1);
	int Mid=(Tree[Hi].l+Tree[Hi].r)/2;
	if(l<=r && r<=Mid)Add(Hi*2,l,r,k);
	else if(l>Mid && l<=r)Add(Hi*2+1,l,r,k);
	else
	{
		if(l<=Mid)Add(Hi*2,l,Mid,k);
		if(r>Mid)Add(Hi*2+1,Mid+1,r,k);
	}
	Tree[Hi].k=Tree[Hi*2].k+Tree[Hi*2+1].k;
}
//--------------------------------------------------------------
ll Num(int Hi,int l,int r)
{
//	printf("%d	%lld\n",Hi,Tree[Hi].k);
	if(Tree[Hi].l==l && Tree[Hi].r==r)
		return Tree[Hi].k;
	Go(Hi,Tree[Hi].r-Tree[Hi].l+1);
	int Mid=(Tree[Hi].l+Tree[Hi].r)/2;
	ll Ans=0;
	if(l<=r && r<=Mid)Ans+=Num(Hi*2,l,r); 
	else if(l>Mid && l<=r)Ans+=Num(Hi*2+1,l,r);
	else
	{
		if(l<=Mid)Ans+=Num(Hi*2,l,Mid);
		if(r>Mid)Ans+=Num(Hi*2+1,Mid+1,r);
	}
	return Ans;
}
//--------------------------------------------------------------
int main()
{
	Sum=0;
	scanf("%d%d",&n,&m);
	getchar();
	Tree_Buil(1,1,n);
	for(int i=1;i<=m;++i)
	{
		int l,r;
		Operation=getchar();
		if(Operation=='M')
		{
			scanf("%d%d",&l,&k);
			getchar();
			Add(1,l,l,k);
		}
		if(Operation=='C')
		{
			scanf("%d%d",&l,&r);
			getchar();
			printf("%lld\n",Num(1,l,r));
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值