可持久化线段树——区间更新hdu4348

和线段树类似,每个结点也要打lazy标记

但是lazy标记和线段树不一样

具体区别在于可持久化后lazy-tag不用往下传递,而是固定在这个区间并不断累加,变成了这个区间固有的性质(有点像分块的标记了)

update就按照这么来

int update(int last,int L,int R,int c,int l,int r){
    int now=++size;
    T[now]=T[last];
    
    if(L<=l && R>=r){
        T[now].sum+=(r-l+1)*c;
        T[now].add+=c;
        return now;
    }
    
    int mid=l+r>>1;
    if(L<=mid)T[now].lc=update(T[last].lc,L,R,c,l,mid);
    if(R>mid)T[now].rc=update(T[last].rc,L,R,c,mid+1,r);
    pushup(l,r,now);
    return now;
}

查询时由于lazytag固定在区间上。所以向下查询的时候要把上层的lazytag的影响都算上,即递归时传递一个上层区间的  影响值(例如add)

ll query(int now,int L,int R,int add,int l,int r){
    if(L<=l && R>=r) return T[now].sum+(ll)add*(r-l+1);
    int mid=l+r>>1;
    ll res=0;add+=T[now].add;
    if(L<=mid)res+=query(T[now].lc,L,R,add,l,mid);
    if(R>mid)res+=query(T[now].rc,L,R,add,mid+1,r);
    return res;
}

此外还有合并维护时,由于子区间没有收到父区间的影响,所以合并时还要算父区间的lazytag

void pushup(int l,int r,int rt){T[rt].sum=T[T[rt].lc].sum+T[T[rt].rc].sum+T[rt].add*(r-l+1);}

最后是完整代码,其实本题版本回滚时还可以吧size往回滚,以此节省内存

/*
主席树区间更新 
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define maxn 100005
ll n,m,a[maxn];
struct Node{int lc,rc;ll sum,add;}T[maxn*25];
int size,rt[maxn];
void pushup(int l,int r,int rt){T[rt].sum=T[T[rt].lc].sum+T[T[rt].rc].sum+T[rt].add*(r-l+1);}
int build(int l,int r){
    int now=++size;
    if(l==r){
        T[now].lc=T[now].rc=0;
        T[now].sum=a[l];
        return now;
    }
    int mid=l+r>>1;
    T[now].lc=build(l,mid);
    T[now].rc=build(mid+1,r);
    pushup(l,r,now);
    return now;
}
int update(int last,int L,int R,int c,int l,int r){
    int now=++size;
    T[now]=T[last];
    
    if(L<=l && R>=r){
        T[now].sum+=(r-l+1)*c;
        T[now].add+=c;
        return now;
    }
    
    int mid=l+r>>1;
    if(L<=mid)T[now].lc=update(T[last].lc,L,R,c,l,mid);
    if(R>mid)T[now].rc=update(T[last].rc,L,R,c,mid+1,r);
    pushup(l,r,now);
    return now;
}
ll query(int now,int L,int R,int add,int l,int r){
    if(L<=l && R>=r) return T[now].sum+(ll)add*(r-l+1);
    int mid=l+r>>1;
    ll res=0;add+=T[now].add;
    if(L<=mid)res+=query(T[now].lc,L,R,add,l,mid);
    if(R>mid)res+=query(T[now].rc,L,R,add,mid+1,r);
    return res;
}
void init(){
    size=0;
    memset(rt,0,sizeof rt);
    memset(T,0,sizeof T);
}
int main(){
    while(scanf("%lld%lld",&n,&m)==2){
        init();
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        
        int cur=0,l,r,c;char op[2];
        rt[cur]=build(1,n);
        while(m--){
            scanf("%s",op);
            if(op[0]=='C'){scanf("%d%d%d",&l,&r,&c);rt[++cur]=update(rt[cur-1],l,r,c,1,n);}
            if(op[0]=='Q'){scanf("%d%d",&l,&r);cout<<query(rt[cur],l,r,0,1,n)<<'\n';}
            if(op[0]=='H'){
                scanf("%d%d%d",&l,&r,&c);
                cout<<query(rt[c],l,r,0,1,n)<<'\n';
            }
            if(op[0]=='B'){scanf("%d",&c);cur=c;}
        }
    //    puts("");
    }    
} 

 

转载于:https://www.cnblogs.com/zsben991126/p/10764596.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值