【线段树】区间求和+区间修改(区间加)

来源:互联网 发布:泰瑞克埃文斯 数据 编辑:程序博客网 时间:2024/05/21 09:45
#include<iostream>#include<cstdio>using namespace std;int n,m,a[1000004];struct data{int l,r,val,lazy,len;}tr[2*1000004];void build(int k,int s,int t) {//建树    tr[k].l=s;tr[k].r=t;tr[k].len=t-s+1;    if(s==t) {tr[k].val=a[s];return;}    int mid=(s+t)>>1;    build(k<<1,s,mid);    build(k<<1|1,mid+1,t);    tr[k].val=tr[k<<1].val+tr[k<<1|1].val;}void pushdown(int k){//pushdown操作    if(!tr[k].lazy) return;    int p=tr[k].lazy;    tr[k<<1].lazy+=p;    tr[k<<1|1].lazy+=p;    tr[k<<1].val+=tr[k<<1].len*p;    tr[k<<1|1].val+=tr[k<<1|1].len*p;    tr[k].lazy=0;}void update(int k,int l,int r,int addval){//区间修改    int ll=tr[k].l,rr=tr[k].r;    if(ll>=l && rr<=r){        tr[k].lazy+=addval;        tr[k].val+=tr[k].len*addval;        return;    }    int mid=(ll+rr)>>1;        if (tr[k].lazy) pushdown(k);    if(l<=mid) update(k<<1,l,min(r,mid),addval);    if(r>mid) update(k<<1|1,max(l,mid+1),r,addval);    tr[k].val=tr[k<<1].val+tr[k<<1|1].val;}int query(int k,int x,int y){//区间求和    int ll=tr[k].l,rr=tr[k].r;    if(x==ll && y==rr) return tr[k].val;    int mid=(ll+rr)>>1;        if (tr[k].lazy) pushdown(k);    if(y<=mid) return query(k<<1,x,y);    else if(x>mid) return query(k<<1|1,x,y);    else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    build(1,1,n);    for(int i=1;i<=m;i++){        int flag;scanf("%d",&flag);        int x,y,z;scanf("%d%d",&x,&y);        if(flag==1) scanf("%d",&z),update(1,x,y,z);        else printf("%d\n",query(1,x,y));    }    return 0;}

输入格式:
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:
输出包含若干行整数,即为所有操作2的结果。

输入样例:
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出样例:
11
8
20

原创粉丝点击