题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某区间每一个数加上 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
) 内。
【样例解释】
代码(lazy标记)
#include
#define ll long long
#define pa pair
const int mod = 998244353;
using namespace std;
inline int read()
{
char ch=getchar();int f=1,x=0;
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,x,y,opt,k;
long long a[100005],sum[400005],lazy[400005];
void build(int l,int r,int p)
{
if (l==r){sum[p]=a[l];return;}
int mid=(l+r)>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void pushdown(int p,int l,int r)
{
if (l==r) return;
int mid=(l+r)>>1;
lazy[p<<1]+=lazy[p];
lazy[p<<1|1]+=lazy[p];
sum[p<<1]+=(ll)(mid-l+1)*lazy[p];
sum[p<<1|1]+=(ll)(r-mid)*lazy[p];
lazy[p]=0;
}
void update(int l,int r,int x,int y,int k,int p)
{
pushdown(p,l,r);
if (l==x&&r==y)
{
lazy[p]+=k;
sum[p]+=(ll)k*(r-l+1);
return;
}
int mid=(l+r)>>1;
if (y<=mid) update(l,mid,x,y,k,p<<1);
else if (x>mid) update(mid+1,r,x,y,k,p<<1|1);
else update(l,mid,x,mid,k,p<<1),update(mid+1,r,mid+1,y,k,p<<1|1);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
ll query(int l,int r,int x,int y,int p)
{
pushdown(p,l,r);
if (l==x&&r==y) return sum[p];
int mid=(l+r)>>1;
if (y<=mid) return query(l,mid,x,y,p<<1);
else if (x>mid) return query(mid+1,r,x,y,p<<1|1);
else return query(l,mid,x,mid,p<<1)+query(mid+1,r,mid+1,y,p<<1|1);
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;i++) a[i]=read();
build(1,n,1);
for (int i=1;i<=m;i++)
{
int opt=read(),x=read(),y=read();
if (opt==1)
{
int k=read();
update(1,n,x,y,k,1);
}
else
{
printf("%lld\n",query(1,n,x,y,1));
}
}
return 0;
}
代码(永久化标记):
#include
#include
#include
#include
#include
using namespace std;
int n,m,x,y,opt,k;
long long a[100005],sum[400005],add[400005];
void build(int l,int r,int p)
{
if (l==r){sum[p]=a[l];return;}
int mid=(l+r)>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void update(int l,int r,int x,int y,int p,int k)
{
if (l==x&&r==y){add[p]+=k;sum[p]+=k*(r-l+1);return;}
int mid=(l+r)>>1;
if (y<=mid) update(l,mid,x,y,p<<1,k);
else if (x>mid) update(mid+1,r,x,y,p<<1|1,k);
else
{
update(l,mid,x,mid,p<<1,k);
update(mid+1,r,mid+1,y,p<<1|1,k);
}
sum[p]=sum[p<<1]+sum[p<<1|1]+add[p]*(r-l+1);
}
long long query(int l,int r,int x,int y,int p)
{
if (l==x&&r==y) return sum[p];
int mid=(l+r)>>1;
if (y<=mid) return query(l,mid,x,y,p<<1)+add[p]*(y-x+1);
else if (x>mid) return query(mid+1,r,x,y,p<<1|1)+add[p]*(y-x+1);
else return query(l,mid,x,mid,p<<1)+query(mid+1,r,mid+1,y,p<<1|1)+add[p]*(y-x+1);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,n,1);
while (m--)
{
scanf("%d%d%d",&opt,&x,&y);
if (opt==1)
{
scanf("%d",&k);
update(1,n,x,y,1,k);
}
else printf("%lld\n",query(1,n,x,y,1));
}
return 0;
}