codevs 1082 线段树练习 3

1082 线段树练习 3 区间修改,区间查询;
时间限制: 3 s
空间限制: 128000 KB
题目等级 : 大师 Master
给你N个数,有两种操作:

1:给区间[a,b]的所有数增加X

2:询问区间[a,b]的数的和。

输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,

再接下来一个正整数Q,每行表示操作的个数,

如果第一个数是1,后接3个正整数,

表示在区间[a,b]内每个数增加X,如果是2,

表示操作2询问区间[a,b]的和是多少。

pascal选手请不要使用readln读入

输出描述 Output Description
对于每个询问输出一行一个答案

样例输入 Sample Input
3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output
9

数据范围及提示 Data Size & Hint
数据范围

1<=n<=200000

1<=q<=200000

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sz=200000+50;
struct seg_tree{
    int l,r;
    long long sum;
    long long ax;
} t[sz<<2];
int n,a,q,x,y,z;
long long  v[sz];
void updata(int m){
    t[m].sum=t[m<<1].sum+t[m<<1|1].sum;
    return ;
}
void build(int m,int ll,int rr){
    t[m].l=ll,t[m].r=rr;
    if(ll==rr) {
        t[m].sum=v[ll];
        return ;
    }
    int mid=(ll+rr)>>1;
    build(m<<1,ll,mid);
    build(m<<1|1,mid+1,rr);
    updata(m);
}
void add(int m,int vv){
    t[m].sum+=(t[m].r-t[m].l+1)*vv;
    t[m].ax+=vv;
    return ;
}
void spread(int m){
    if(t[m].ax){
        add(m<<1,t[m].ax);
        add(m<<1|1,t[m].ax);
        t[m].ax=0;
        //这里要改为0!! 否则用while会死循环
    }
    return ;
}
long long ask(int m,int ll,int rr){
    if(t[m].l>=ll&&t[m].r<=rr) return t[m].sum;
    int mid=t[m].l+t[m].r>>1;
    long long ans=0;
    spread(m);
    if(mid>=ll) ans+=ask(m<<1,ll,rr);
    if(mid<rr) ans+=ask(m<<1|1,ll,rr);
    return ans;
}
void change(int m,int ll,int rr,int vv){
    if(t[m].l>=ll&&t[m].r<=rr) {
        add(m,vv);return;
    }
    int mid=(t[m].l+t[m].r)>>1;
    spread(m);
    if(mid>=ll) change(m<<1,ll,rr,vv);
    if(mid<rr) change(m<<1|1,ll,rr,vv);
    updata(m);
    return ;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
    build(1,1,n);

    scanf("%d",&q);
    while(q--){
        scanf("%d",&a);
        if(a==1){
            scanf("%d%d%d",&x,&y,&z);
            change(1,x,y,z);
        //  for(int i=1;i<=n*4;i++)
        //printf("i= %d  t[i].l= %d  t[i].r= %d  t[i].sum= %d  t[i].ax= %d\n",i,t[i].l,t[i].r,t[i].sum,t[i].ax);
        }
        else scanf("%d%d",&x,&y),printf("%lld\n",ask(1,x,y));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值