__BAI__ @ 2023-01-12 21:48:56
#include<bits/stdc++.h>
using namespace std;
inline long long read(){
long long x=0,f=1;
char ch=getchar();
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 lazy[400005],tree[400005],n,a[100005],m,x,y,k,z;
void built(int d,int l,int r){
if(l>=r)return;
if(l==r-1){tree[d]=a[l];return;}
int mid=(l+r)/2;
int l_kid=d*2;
int r_kid=d*2+1;
built(l_kid,l,mid);
built(r_kid,mid,r);
tree[d]=tree[l_kid]+tree[r_kid];
}
void f(int d,int l,int r,int v){
lazy[d]+=v;
tree[d]+=v*(r-l);
}
void add(int d,int l,int r,int p,int q,int v){
if(p==l and q==r){f(d,l,r,v);return;}
int mid=(l+r)/2;
int l_kid=d*2;
int r_kid=d*2+1;
if(p>=mid)add(r_kid,mid,r,p,q,v);
else if(q<=mid)add(l_kid,l,mid,p,q,v);
else{
add(l_kid,l,mid,p,mid,v);
add(r_kid,mid,r,mid,q,v);
}
tree[d]=tree[l_kid]+tree[r_kid];
}
int get(int d,int l,int r,int p,int q){
if(l==p and r==q){return tree[d];}
int mid=(l+r)/2;
int l_kid=d*2;
int r_kid=d*2+1;
if(lazy[d]){f(l_kid,l,mid,lazy[d]);f(r_kid,mid,r,lazy[d]);lazy[d]=0;}
if(p>=mid)return get(r_kid,mid,r,p,q);
if(q<=mid)return get(l_kid,l,mid,p,q);
return get(l_kid,l,mid,p,mid)+get(r_kid,mid,r,mid,q);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
built(1,1,n+1);
while(m--){
z=read();
if(z==1){
x=read(),y=read(),k=read();
add(1,1,n+1,x,y+1,k);
}else{
x=read(),y=read();
printf("%d\n",get(1,1,n+1,x,y+1));
}
}
}
by Rikora @ 2023-01-12 22:30:35
如果细节上没什么问题的话,是不是add的时候没有检查懒标记?add和get都应该在查询一个结点lazy不为0的时候把懒标记下推吧,代码里好像只有get下推了,add没下推,导致答案都偏小。
by Rikora @ 2023-01-12 22:54:47
刚才口胡了一下,删掉重发(
原因在于add在左右递归之后要把左右子节点的和重新赋值给父节点,如果之前父节点的懒惰标记没有推下去的话,此时左右子节点的值都是偏小的,它们的和也小于父节点正常的新值。
by __BAI__ @ 2023-01-13 08:12:53
好的,谢谢