线段树模板1
如题,已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 k。
- 求出某区间每一个数的和。
输入格式
第一行包含两个整数 n,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 nn个用空格分隔的整数,其中第 i个数字表示数列第 i项的初始值。
接下来 mm 行每行包含 3或 4 个整数,表示一个操作,具体如下:
1 x y k
:将区间 [x, y][x,y] 内每个数加上 k。2 x y
:输出区间 [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
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int a[maxn + 2];
struct tree{
int l,r;
long long pre,add;
}t[4 * maxn + 2];
void build(int p,int l,int r){
t[p].l = l,t[p].r = r;
if(l == r){
t[p].pre = a[l];
return ;
}
int mid = l + r >> 1;
build(p * 2,l,mid);
build(p * 2 + 1,mid + 1,r);
t[p].pre = t[p * 2].pre + t[p * 2 + 1].pre;
}
void spread(int p)
{
if(t[p].add){
t[p * 2].pre += t[p].add * (t[p * 2].r - t[p * 2].l + 1);
t[p * 2 + 1].pre += t[p].add * (t[p * 2 + 1].r - t[p * 2 + 1].l + 1);
t[p * 2].add += t[p].add;
t[p * 2 + 1].add += t[p].add;
t[p].add = 0;
}
}
void change(int p,int x,int y,int z)
{
if(x <= t[p].l && y >= t[p].r){
t[p].pre += (long long)z * (t[p].r - t[p].l + 1);
t[p].add += z;
return;
}
spread(p);
int mid = t[p].l + t[p].r >> 1;
if(x <= mid)change(p * 2,x,y,z);
if(y > mid)change(p * 2 + 1,x,y,z);
t[p].pre = t[p * 2].pre + t[p * 2 + 1].pre;
}
long long ask(int p,int x,int y)
{
if(x <= t[p].l && y >= t[p].r)return t[p].pre;
spread(p);
int mid = t[p].l + t[p].r >> 1;
long long ans = 0;
if(x <= mid)ans += ask(p * 2,x,y);
if(y > mid) ans += ask(p * 2 + 1,x,y);
return ans;
}
int main()
{
int n,m;
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 q,x,y,z;
scanf("%d",&q);
if(q == 1){
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z);
}else{
scanf("%d%d",&x,&y);
printf("%lld\n",ask(1,x,y));
}
}
return 0;
}