模板线段树1

来源:互联网 发布:mac重新启动快捷键 编辑:程序博客网 时间:2024/06/06 02:11

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式:

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

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

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

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

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

输出格式:

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


#include<cstdio>using namespace std;struct q{int l,r;long long t;}tree[400001];int n,m,a[100001],lazy[400001];void build(int x,int l,int r){if (l==r){tree[x].l=tree[x].r=l;tree[x].t=a[l];return;}tree[x].l=l;tree[x].r=r;lazy[x]=0;int mid=(l+r)/2;build(x*2,l,mid);build(x*2+1,mid+1,r);tree[x].t=tree[x*2].t+tree[x*2+1].t;}void pushdown(int x){//if(tree[x].l==tree[x].r) return;if (lazy[x]){lazy[x*2]+=lazy[x];lazy[x*2+1]+=lazy[x];tree[x*2].t+=lazy[x]*(tree[x*2].r-tree[x*2].l+1);tree[x*2+1].t+=lazy[x]*(tree[x*2+1].r-tree[x*2+1].l+1);lazy[x]=0;}}void doit(int x,int l,int r,int c){if (tree[x].l>r||tree[x].r<l) return;if (tree[x].l>=l&&tree[x].r<=r) {lazy[x]+=c;tree[x].t+=c*(tree[x].r-tree[x].l+1);return;}pushdown(x);int mid=(tree[x].l+tree[x].r)/2;if (l<=mid)doit(x*2,l,r,c);if (r>mid)doit(x*2+1,l,r,c);tree[x].t=tree[x*2].t+tree[x*2+1].t;}long long find(int x,int l,int r){if (tree[x].l>r||tree[x].r<l) return 0;if (tree[x].l>=l&&tree[x].r<=r) return tree[x].t;pushdown(x);long long t=0;int mid=(tree[x].l+tree[x].r)/2;if (l<=mid)t+=find(x*2,l,r); if (r>mid)t+=find(x*2+1,l,r);return t;}int main(){freopen("1.in","r",stdin);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 x,l,r,c;scanf("%d",&x);if (x==1){scanf("%d%d%d",&l,&r,&c);doit(1,l,r,c);}else{scanf("%d%d",&l,&r);printf("%lld\n",find(1,l,r));}}return 0;}


原创粉丝点击