计蒜客:区间整数操作-区间更新-区间和

给出N个整数A1,A2,..,Av,你需要处理区间加,区间求和。
输入格式
第一行两个整数N和Q(1≤N,Q≤105)。
第二行N个整数,表示A1,A2...Av(|A;≤109)的初始值。
接下来Q行,每行一个操作:
cabc,表示Aa,Aa+1…Ab每个数加c(lcl≤10000)。
Qab,表示询问Aa,Aa+1..Ab的和,答案可能超过32位整数。
输出格式
对于所有Q询问,一行输出一个答案。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
/*区间更新,区间加值--区间求和*/

const int MAX_N = 1e5+5;
ll s[4 * MAX_N],col[4 * MAX_N];
int n,q;

//父节点合并 
void up(int p){
    s[p] = s[p * 2] + s[p * 2 + 1];
}

//向下更新一层  区间更新使用延迟更新的思想提高效率
void down(int p, int l, int r){
    if(col[p]){
        int mid = (l + r) / 2;
        s[p * 2] += col[p] * (mid - l + 1);
        s[p * 2 + 1] += col[p] * (r - mid);
        col[p * 2] += col[p];
        col[p * 2 + 1] += col[p];
        col[p] = 0;
    }
}

//更新 
void modify(int p,int l,int r,int x,int y,int c){
    if(x <= l && r <=y){
		s[p] += (r - l + 1) * c; //对父结点修改 如何是求区间最值而不是求和该如何修改呢? 
        col[p] += c; //标记子节点需要延迟更新 
        return;
    }
    down(p, l, r);//向下更新一层 
    int mid = (l + r)/2;
    if(x <= mid){
        modify(p * 2, l, mid, x, y, c);
    }
    if(y > mid){
        modify(p * 2 + 1, mid + 1,r,x,y,c);
    }
    up(p);
}

//查询 
ll query(int p,int l,int r,int x,int y){
	if(x <= l && r <= y){
        return s[p];
    }
    down(p,l,r);//如果没有return,这时子节点必须更新了  就向下更新一层
    int mid = (l + r) / 2;
	ll res = 0;
    if(x <= mid){
		res += query(p * 2, l,mid,x,y);
    }
    if(y > mid){
        res += query(p * 2 + 1,mid + 1,r,x,y);
    }
    return res;
}

int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		ll d;
		scanf("%ld",&d);
		modify(1,1,n,i,i,d);
	}
	char ins;
	while(q--){
		scanf(" %c",&ins);
		int a,b;
		ll c;
		if(ins=='Q'){
			scanf("%d%d",&a,&b);
			printf("%lld\n",query(1,1,n,a,b));
		}else{
			scanf("%d%d%ld",&a,&b,&c);
			modify(1,1,n,a,b,c);
		}
	}
	return 0;
} 
posted @ 2019-02-13 14:50  fishers  阅读(365)  评论(0编辑  收藏  举报