本人自己出的一道题:
已知有N个数,其中第i个数的只是a[i],对这i个数进行q个操作,每次先输入op,代表操作,若op==0,则输入x,y,求a[x]+......+a[y]的值。若op==1则 输入x,y,z,将a[x]......a[y]之间的每一个(包括a[x],a[y])加z。先输入n,q(n<=300000,q<=300000)
接下来一行n个数,其中第i个数表示a[i]。接下来q行,先输入操作op,然后在对应地输入若op=0,则输出这个和,不然对应地进行操作。并且输出是一行一个数 (z<=10000000)
样例输入:
10 6
1 2 3 4 5 6 7 8 9 10
1 1 5 -5
1 2 3 -6
1 2 5 5
1 2 5 8
1 4 9 -6
0 2 7
样例输出:23
#include
#include
#include
#include
using namespace std;
const int N=(1<<19)+10;
int l[N<<1],r[N<<1];
long long sum[N<<1],lazy[N<<1];//lazy也可以写成add
int q,op,x,y,z,n;
long long v[N],ans;
void build(){//建树
int s=1;
while(s<=n)s*=2;
for(int i=s*2-1;i>=s;i--){
l[i]=r[i]=i-s+1;
sum[i]=v[i-s+1];lazy[i]=0;
}
for(int i=s-1;i>=1;i--){
lazy[i]=0;
l[i]=l[i*2];r[i]=r[i*2+1];
sum[i]=sum[i*2+1]+sum[i*2];
}
}
void pushdown(int i){//下方操作,将当前的lazy下放
if(lazy[i]){//这样下放,保证每次修改都能有效的进行
lazy[2*i]+=lazy[i];lazy[2*i+1]+=lazy[i];
sum[2*i]+=(r[2*i]-l[2*i]+1)*lazy[i];
sum[2*i+1]+=(r[2*i+1]-l[2*i+1]+1)*lazy[i];
lazy[i]=0;
}
}
void update(int l1,int r1,int i,int k){//更新操作,每次不要忘记下放
if(l1<=l[i]&&r[i]<=r1){
lazy[i]+=k;
sum[i]+=(r[i]-l[i]+1)*k;
return ;
}
int mid=(l[i]+r[i])/2;
pushdown(i);
if(l1>mid)update(l1,r1,i*2+1,k);
else if(r1<=mid)update(l1,r1,i*2,k);
else {
update(l1,mid,i*2,k);
update(mid+1,r1,i*2+1,k);
}
sum[i]=sum[i*2]+sum[i*2+1];
}
void ask(int l1,int r1,int i){//询问操作,每次不要忘记下放
if(l1<=l[i]&&r[i]<=r1){
ans+=sum[i];
return ;
}
pushdown(i);
int mid=(l[i]+r[i])/2;
if(l1>mid)ask(l1,r1,i*2+1);
else if(r1<=mid)ask(l1,r1,i*2);
else {
ask(l1,mid,i*2);
ask(mid+1,r1,i*2+1);
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%lld",&v[i]);
build();
for(int i=1;i<=q;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&x,&y,&z);
update(x,y,1,z);
}
else {
scanf("%d%d",&x,&y);
ans=0;ask(x,y,1);
printf("%d\n",ans);
}
}
}