题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某区间每一个数加上 kk。
求出某区间每一个数的和。
输入格式
第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:
1 x y k:将区间 [x, y][x,y] 内每个数加上 kk。
2 x y:输出区间 [x, y][x,y] 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
输入输出样例
输入 #1复制
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出 #1复制
11
8
20
说明/提示
对于 30%30% 的数据:n \le 8n≤8,m \le 10m≤10。
对于 70%70% 的数据:n \le {10}^3n≤10
3
,m \le {10}^4m≤10
4
。
对于 100%100% 的数据:1 \le n, m \le {10}^51≤n,m≤10
5
。
保证任意时刻数列中任意元素的和在 [-2^{63}, 2^{63})[−2
63
,2
63
) 内。
模板题,体会到了pushdown操作的绝妙魅力。这个题用到这个算法比普通线段树快了近4倍的速度。本题注意区间修改和区间查询都要先对当前结点进行pushdown(来自无数次WA的领悟)。
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
#include <map>
#include <algorithm>
#define maxn 1000000
using namespace std;
typedef long long ll;
ll n,m;
typedef struct Tree
{
ll sum;
ll l;
ll r;
ll lazy;
Tree(){l=r=sum=lazy=0;}
} T;
T a[maxn];
ll num[maxn];
void update(ll k)
{
a[k].sum = a[k<<1].sum + a[k<<1|1].sum;
return ;
}
void build_tree(ll k, ll l, ll r)
{
a[k].l = l;
a[k].r = r;
a[k].lazy = 0;
if(l==r)
{
a[k].sum = num[l];
return ;
}
ll mid = (l+r)>>1;
build_tree(k<<1, l, mid);
build_tree(k<<1|1 , mid+1, r);
update(k);
}
void change(ll k, ll pos, ll obj)
{
if(a[k].l==a[k].r)
{
a[k].sum = obj;
return ;
}
ll mid = (a[k].l + a[k].r)>>1;
if(pos<=mid) change(k<<1, pos , obj);
else change(k<<1|1,pos,obj);
update(k);
}
void pushdown( ll k)
{
if(a[k].l==a[k].r)
{
a[k].lazy = 0;
return ;
}
a[k<<1].sum += (a[k<<1].r - a[k<<1].l + 1)*a[k].lazy;
a[k<<1|1].sum += (a[k<<1|1].r - a[k<<1|1].l +1) *a[k].lazy;
a[k<<1].lazy += a[k].lazy;
a[ k<<1|1].lazy += a[k].lazy;
a[k].lazy = 0;
}
void changeSegment( ll k, ll l, ll r, ll x)
{
if(a[k].lazy) pushdown(k);
if(a[k].l==l&&a[k].r==r)
{
a[k].sum += (a[k].r-a[k].l+1)*x;
a[k].lazy += x;
return ;
}
ll mid = (a[k].l+a[k].r)>>1;
if(mid>=r) changeSegment(k<<1,l,r,x);
else if (mid<l) changeSegment(k<<1|1,l,r,x);
else changeSegment(k<<1,l,mid,x) , changeSegment(k<<1|1,mid+1,r,x);
update(k);
}
ll query( ll k, ll l, ll r)
{
if(a[k].lazy) pushdown(k);
if(a[k].l==l&&a[k].r==r)
return a[k].sum;
ll mid = (a[k].l+a[k].r)>>1;
if(mid>=r) return query(k<<1,l,r);
else if(mid<l) return query(k<<1|1,l,r);
return query(k<<1,l,mid) + query(k<<1|1,mid+1,r);
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
scanf("%lld",&num[i]);
build_tree(1,1,n);
while(m--)
{
ll cnt, x, y;
scanf("%lld %lld %lld",&cnt,&x,&y);
if(cnt==1)
{
ll val;
scanf("%lld",&val);
changeSegment(1,x,y,val);
}
else
{
printf("%lld\n", query(1,x,y));
}
}
return 0;
}