P3374 【模板】树状数组 1 线段树解题

P3374 【模板】树状数组 1
题解:
线段树的单点更新,区间查询,注意线段树的结点个数是原数组的4倍

#include<iostream>
#include<cstdio>
using namespace std;
long long s[2000100],a[501000],n,m,dx,dy;
void btr(int rt,int l,int r)//建树
{
	if(l==r)//叶结点等于原数组的值
	{
		s[rt]=a[l];
	}
	else
	{
		int ls=rt*2,rs=rt*2+1,mid=(l+r)/2;//二分递归求左右子树
		btr(ls,l,mid);
		btr(rs,mid+1,r);
		s[rt]=s[ls]+s[rs];//回溯求该结点的和
	}
}
void su(int x,int k,int rt,int l,int r)//单点更新
{
	if(l==r)
	{
		s[rt]+=k;
		return;
	}
	int mid=(l+r)/2,ls=rt*2,rs=rt*2+1;
	if(x>=l&&x<=mid)
	{
		su(x,k,ls,l,mid);
	}
	else
	{
		su(x,k,rs,mid+1,r);
	}
	s[rt]+=k;
}
long long sc(int x,int y,int rt,int l,int r)//区间查询,查询区间[x,y],结点rt,对应区间[l,r]
{
	if(l>=dx&&r<=dy)//查询区间包括结点区间直接返回
	{
		return s[rt];
	}
	long long ans=0;
	int mid=(l+r)/2,ls=rt*2,rs=rt*2+1;
	if(y<=mid)//只有左子树
	{
		ans+=sc(x,y,ls,l,mid);
	}
	else if(x>mid)//只在右子树
	{
		ans+=sc(x,y,rs,mid+1,r);
	}
	else//两个均包括
	{
		ans=ans+sc(x,mid,ls,l,mid)+sc(mid+1,y,rs,mid+1,r);
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	btr(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		cin>>c>>x>>y;
		if(c==1)
		{
			su(x,y,1,1,n);
		}
		else
		{
			dx=x;dy=y;
			cout<<sc(x,y,1,1,n)<<endl;
		}
	}
}

  

posted @ 2022-03-07 15:13  心悟&&星际  阅读(32)  评论(0编辑  收藏  举报