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; }