线段树模板

问题 A: 子数列连续和

#include <iostream>
using namespace std;
typedef unsigned long long ll;

const int maxn=1e5+5;
int a[maxn];
struct node
{
    int l,r;
    ll sum;
}e[maxn<<2];

void build(int l,int r,int index)///左端点l,右端点r,节点序号index
{

    e[index]={l,r,0};///赋值左右端点
    if(l==r) {e[index].sum=a[l];  return;}///递归到根节点了,赋值,回溯
    else///二分递归建树
    {
        int mid=(l+r)/2;///中点mid
        build(l,mid,index*2);///建左子树,区间(l,mid),左子树节点的序号为index*2
        build(mid+1,r,index*2+1);///建右子树,区间(mid+1,r),右子树节点的序号为index*2+1
        e[index].sum=e[index*2].sum+e[index*2+1].sum;///维护区间和,等于左右区间的和
    }
}

void updata(int num,int value,int index)
{
    int l=e[index].l,r=e[index].r;///获取左右端点
    if(l==num&&r==num)  {e[index].sum+=value; return;}///更新值(注意更新方式,看是+还是直接改变),并且要记得返回
    else ///递归更新树
    {
        int mid=(l+r)/2;
        if(num>mid)  updata(num,value,index*2+1);///目标在右子树中
        else if(num<=mid) updata(num,value,index*2);  ///目标在左子树中
        e[index].sum=e[index*2].sum+e[index*2+1].sum;///回溯,更新区间
    }
}

ll query(int l,int r,int index)
{
    int L=e[index].l,R=e[index].r;
    if(l<=L&&r>=R) return e[index].sum;///树上的该区间(L,R)完全包含在目标区间内,返回
    else
    {
        int mid=(L+R)/2;
        if(mid<l) query(l,r,index*2+1);///目标区间完全在右区间
        else if(mid>=r) query(l,r,index*2);///目标区间完全在左区间,记得带等号
        else///目标区间左右区间都有
        {
            return query(l,r,index*2)+query(l,r,index*2+1);
        }
    }
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,n,1);///区间(1,n),序号从第1个开始建起
    //for(int i=1;i<=n;i++) cout<<e[i].sum<<endl;
    for(int i=1;i<=m;i++)
    {
        int q,c,d;
        scanf("%d%d%d",&q,&c,&d);
        if(q==1)  updata(c,d,1);
        else      {cout<<query(c,d,1)<<endl;}
    }
}
/*
4 2
7 6 3 5
1 1 4
2 1 2

ans=17
*/





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值