Description
对于一个长度为 \(n\) 的序列 \(a_1, a_2, \ldots, a_n\), 其前缀和 (Prefix Sum)\(S_i\) 为前 \(i\) 个元素的和, 即 \(\sum_{k=1}^{i} a_i\). 而前缀和的前缀和 (Preprefix sum) 就是把前缀和序列 \(S_1, S_2, \ldots, S_n\) 作为原序列, 再求一次前缀和. 记再次求得的前缀和序列的第 \(i\) 位为 \(SS_i\).
现在给定一个长度为 \(n\) 的序列 \(a_1, a_2, \ldots, a_n\), 有两种操作:
Modify i x
将 \(a_i\) 的值改为 \(x\);Query i
询问 \(SS_i\) 的值.
请编写一个程序来实现这两种操作.
Input
第一行给出两个整数 \(n, m\). 分别表示序列长度和操作个数;
接下来一行有 \(n\) 个数, 即给定的序列 \(a_1, a_2, \ldots, a_n\);
接下来 \(m\) 行, 每行对应一个操作, 格式见题目描述.
Output
对于每个询问操作, 输出一行, 表示所询问的 \(SS_i\) 的值.
Sample Input
5 3
1 2 3 4 5
Query 5
Modify 3 2
Query 5
Sample Output
35
32
Data Range
对于所有数据, 满足 \(1 \leq n, m \leq 10^5\), 且在任意时刻 \(0 \leq a_i \leq 10^5\).
Explanation
我们考虑这样一个递推公式:
\[\begin{aligned} SS_n &= \sum_{i=1}^{n} S_i\\ &= \sum_{i=1}^{n} \sum_{j=1}^{i} a_i\\ &= \sum_{i=1}^{n} (n + 1 - i) \cdot a_i\\ &= n \cdot \sum_{i=1}^{n} a_i - \sum_{i=1}^{n} (i - 1) \cdot a_i \end{aligned}\]
然后发现左边和右边两个都是可以分别用树状数组或线段树维护的, 但是树状数组代码行数 更少, 所以我就写了树状数组.
所以说这是一道结论题, 随便推一下就可以得到结果了.
Source Code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long lli;
const int maxn = 100100;
class BinaryIndexedTree
{
public:
lli dat[maxn];
int n;
lli query(int x)
{
lli sum = 0;
for (; x > 0; x -= x & -x)
sum += dat[x];
return sum;
}
void change(int x, lli v)
{
for (; x <= n; x += x & -x)
dat[x] += v;
return ;
}
void init(int n)
{
this->n = n;
memset(dat, 0, sizeof(dat));
return ;
}
} bit1, bit2;
int n, m;
lli arr[maxn];
char str[64];
int main(int argc, char** argv)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &arr[i]);
// Initializing BIT tree.
bit1.init(n);
bit2.init(n);
for (int i = 1; i <= n; i++) {
bit1.change(i, arr[i]);
bit2.change(i, (i-1) * arr[i]);
}
// Can you answer these queries?
for (int idx = 1; idx <= m; idx++) {
lli b; lli c;
scanf("%s", str);
if (str[0] == 'Q') {
scanf("%lld", &b);
lli res = b * bit1.query(b) - bit2.query(b);
printf("%lld\n", res);
} else if (str[0] == 'M') {
scanf("%lld%lld", &b, &c);
lli tmp = c - arr[b];
arr[b] += tmp;
bit1.change(b, tmp);
bit2.change(b, (b-1) * tmp);
}
}
return 0;
}