洛谷p3372 区间求和+区间更新 一点理解

在这里插入图片描述
2.更新 要更新的区间值在L-R范围中,根据lazy-tag的原理 不用更新到每个根节点
实际上只需要在线段树已经分得的区间l-r中找出一个或多个包含在L-R中的l-r组成L-R
并且可以根据公式直接求得这个区间结点更新后的值
于是可以把函数分成3个部分
两个结束条件 结束条件1 要更新的区间不在l到r中 直接舍弃掉这个区间
结束条件2 找到了包含在L-R中的l-r区间 直接更新它 不再往后考虑
第3个部分 一部分的l-r属于L-R 需要分出有用的部分进行更新 无用的部分舍弃
并且一旦进行了拆分说明已经进入了子树 根据lazy-tag的原理,如果子节点之前的父节点恰好被更新到此停止 tag值不为0 我们就必须考虑利用父节点保存的tag值更新子节点 否则值会出错(会少加之前的tag)
在这里插入图片描述

在这里插入图片描述
所有代码:


#include <iostream>

using namespace std;
/*
1.创建
2.求和
3.更新
*/
long long a[100001];
struct tree
{
    long long num;
    int tag=0;
}t[400001];
void creat_tree(long long a[],tree t[],int node,int l,int r)
{
    if(r==l)
    {
        t[node].num=a[r];
    }
    else
    {
    int mid=(l+r)/2;
    creat_tree(a,t,node*2,l,mid);
    creat_tree(a,t,node*2+1,mid+1,r);
    t[node].num=t[node*2+1].num+t[node*2].num;
    }
}
void update_tree(long long a[],tree t[],int node,int l,int r,int L,int R,int k)
{
    if(L>r||R<l)//要更新的区间不在l到r的范围中
    {
        return;
    }
    else if(L<=l&&R>=r)//要更新的区间包含l到r的范围
    {
        t[node].num+=(r-l+1)*k;
        t[node].tag+=k;//更新tag
    }
    else//部分包含
   {
           int mid=(l+r)/2;
           if(t[node].tag!=0){
    t[node*2].tag+=t[node].tag;//对右边子结点更新
    t[node*2].num+=(mid-l+1)*t[node].tag;
    t[node*2+1].tag+=t[node].tag;//对左边子结点更新
    t[node*2+1].num+=(r-mid)*t[node].tag;
        t[node].tag=0;}

    update_tree(a,t,node*2,l,mid,L,R,k);
    update_tree(a,t,node*2+1,mid+1,r,L,R,k);
   
    t[node].num=t[node*2].num+t[node*2+1].num;

   }
}
long long query_tree(long long a[],tree t[],int node,int l,int r,int L,int R)
{
    long long query_l,query_r;
    if(L>r||R<l)
    {
        return 0;
    }
    else if(L<=l&&R>=r)
    {
        return t[node].num;
    }
    else
    {
    int mid=(l+r)/2;
    if(t[node].tag!=0){
    t[node*2].tag+=t[node].tag;//对右边子结点更新
    t[node*2].num+=(mid-l+1)*t[node].tag;
    t[node*2+1].tag+=t[node].tag;//对左边子结点更新
    t[node*2+1].num+=(r-mid)*t[node].tag;
    t[node].tag=0;}
    t[node].num=t[node*2].num+t[node*2+1].num;
    query_l=query_tree(a,t,node*2,l,mid,L,R);
    query_r=query_tree(a,t,node*2+1,mid+1,r,L,R);
    }
    return query_l+query_r;
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    creat_tree(a,t,1,1,n);
    int temp;int x,y,k;
    while(m--)
    {
        cin>>temp;
        if(temp==2)
        {
            cin>>x>>y;
            cout<<query_tree(a,t,1,1,n,x,y)<<endl;
        }
        else if(temp==1)
        {
            cin>>x>>y>>k;
            update_tree(a,t,1,1,n,x,y,k);
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值