hdu4348 To the moon (可持久化线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4348

题目大意:给定含有n个数的序列,有以下四种操作

1.C l r d:表示对区间[l,r]中的数加上d,并且时间加1

2.Q l r:询问当前时间区间[l,r]的和

3.H l r t:询问时间t区间[l,r]的和

4.B t :时间回到t

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
2 4
0 0
C 1 1 1
C 2 2 -1
Q 1 2
H 1 2 1
Sample Output
4
55
9
15

0
1

 

解题思路:用线段树求区间和时可以不用把lazy标记下传,因为每次都下传的话消耗的空间会很大,很可能爆内存,我们可以直接在询问时,把当前区间的懒惰标记用一个参数传下去,然后找到要求和的区间时,直接把从上到下的懒惰标记累加和乘以区间长度再加上这段区间原本的和就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
struct node{
    int l,r;
    ll lazy,sum;
}tree[maxn*30];
int n,m,t,cnt,root[maxn];
void pushup(int rt,int l,int r){
    tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum+tree[rt].lazy*(r-l+1);
}
void build(int &rt,int l,int r){
    rt=++cnt;
    tree[rt].lazy=0;
    if(l==r){
        scanf("%lld",&tree[rt].sum);
        return;
    }
    int mid=(l+r)/2;
    build(tree[rt].l,l,mid);
    build(tree[rt].r,mid+1,r);
    pushup(rt,l,r);
}
void update(int &now,int pre,int L,int R,int val,int l,int r){
    now=++cnt,tree[now]=tree[pre];
    if(L<=l&&R>=r){
        tree[now].sum+=1ll*(r-l+1)*val;
        tree[now].lazy+=val;
        return;
    }
    int mid=(l+r)/2;
    if(L<=mid) update(tree[now].l,tree[pre].l,L,R,val,l,mid);
    if(R>mid) update(tree[now].r,tree[pre].r,L,R,val,mid+1,r);
    pushup(now,l,r);
}
ll query(int now,int L,int R,int lazy,int l,int r){
    if(L<=l&&R>=r){
        return tree[now].sum+1ll*(r-l+1)*lazy;
    }
    int mid=(l+r)/2; ll res=0;
    lazy+=tree[now].lazy;
    if(mid>=L) res+=query(tree[now].l,L,R,lazy,l,mid);
    if(mid<R) res+=query(tree[now].r,L,R,lazy,mid+1,r);
    return res;
}
int main(){
    char op[10];
    scanf("%d%d",&n,&m);
    build(root[0],1,n);
    int l,r,val,T;
    t=0;
    while(m--){
        scanf("%s",op);
        if(op[0]=='C'){
            scanf("%d%d%d",&l,&r,&val);
            t++;
            update(root[t],root[t-1],l,r,val,1,n);
        }else if(op[0]=='Q'){
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(root[t],l,r,0,1,n));
        }else if(op[0]=='H'){
            scanf("%d%d%d",&l,&r,&T);
            printf("%lld\n",query(root[T],l,r,0,1,n));
        }else if(op[0]=='B'){
            scanf("%d",&t);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/zjl192628928/p/11230113.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值