Luogu 4868 Preprefix sum

类似于树状数组维护区间的方法。

每一次询问要求$\sum_{i = 1}^{n}\sum_{j = 1}^{i}a_j$。

展开一下:

    $\sum_{i = 1}^{n}\sum_{j = 1}^{i}a_j = \sum_{i = 1}^{n}a_i * (n - i + 1) = (n + 1)\sum_{i = 1}^{n}a_i - \sum_{i = 1}^{n}a_i * i$

用两个树状数组分别维护一下$\sum_{i = 1}^{n}a_i$和$\sum_{i = 1}^{n}a_i * i$就可以了。
时间复杂度$O((n + q)logn)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 1e5 + 5;

int n, qn;
ll a[N];

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op; 
}

namespace Bit {
    ll sum1[N], sum2[N];
    
    #define lowbit(p) (p & (-p))
    
    inline void modify(int p, ll v, ll *arr) {
        for(; p <= n; p += lowbit(p))
            arr[p] += v;
    }
    
    inline ll query(int p, ll *arr) {
        ll res = 0LL;
        for(; p > 0; p -= lowbit(p))
            res += arr[p];
        return res;
    }
    
} using namespace Bit;

int main() {
    read(n), read(qn);
    for(int i = 1; i <= n; i++) {
        read(a[i]);
        modify(i, a[i], sum1);
        modify(i, 1LL * a[i] * i, sum2);
    }
    
    for(char op[7]; qn--; ) {
        scanf("%s", op);
        if(op[0] == 'Q') {
            int x; read(x);
            printf("%lld\n", 1LL * (x + 1) * query(x, sum1) - query(x, sum2)); 
        } else {
            int x; ll v;
            read(x), read(v);
            modify(x, -a[x], sum1), modify(x, -1LL * a[x] * x, sum2);
            modify(x, v, sum1), modify(x, v * x, sum2);
            a[x] = v; 
        }
    }
    
    return 0;
}
View Code

 

posted @ 2018-09-20 11:16  CzxingcHen  阅读(146)  评论(0编辑  收藏  举报