POJ-3468-A Simple Problem with Integers

树状数组,区间更新,区间求和。
设原数组为p(),
delta(i)表示p数组第i个数及第i个数之和都要加上delta(i)。
sum()表示p()的前缀和 。
num()表示i*delta(i)的前缀和。
若对[a, b]区间中的数加上c,则只需delta(a) += c, delta(b+1) -= c;
则a到b的区间之和 = sum[b] + segma(delta(i) * (x - i + 1) - (sum[a] +segma(delta(i) * (x - i + 1)).
= sum(b) + (x+1) * segma(delta(i)) - segma(i*delta(i)) - (sum(a) + (x+1) * segma(delta(i)) - segma(i*delta(i) ).
所以只要维护delta(i)前缀和的树状数组以及i*delta(i)的前缀和的树状数组

#include <iostream> 
#include <cstdio> 
#include <cstring>
#define maxn 100005
#define INF 1e9
using namespace std;
typedef long long ll;

ll sum[maxn], num[maxn], add[maxn];
int n, q;

void Update(int i, int m, int h){

    while(i <= n){
        num[i] += m;
        add[i] += h;
        i += i & -i;
    }
} 
void Query(int i, ll &s1, ll &s2){

    while(i >= 1){
        s1 += num[i];
        s2 += add[i];
        i -= i & -i;
    }
}
int main(){

// freopen("in.txt", "r", stdin);

    while(cin >> n >> q){

        char ch;
        int a, b, c;
        for(int i = 1; i <= n; i++){
            scanf("%lld ", sum + i);
            sum[i] += sum[i-1];
        }
        memset(num, 0, sizeof(num));
        memset(add, 0, sizeof(add));
        for(int i = 0; i < q; i++){

            scanf("%c", &ch);
            if(ch == 'Q'){
                scanf("%d%d ", &a, &b);
                ll h1 = 0, h2 = 0, s1 = 0, s2 = 0;
                Query(a-1, h1, h2);
                Query(b, s1, s2);
                printf("%lld\n", sum[b] + (b+1) * s1 - s2 - (sum[a-1] + a * h1 - h2));
            } 
            else{
                scanf("%d%d%d ", &a, &b, &c); 
                ll s1 = c, s2 = a * c;
                Update(a, s1, s2);
                s1 = -c, s2 = (b+1) * (-c);
                Update(b+1, s1, s2);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(POJ-3468-A Simple Problem with Integers)