Bzoj 3155 Preprefix sum
题意:
长度为n的序列,m次操作
操作有两种:1.询问前缀和的前缀和;2.修改某个ai的值
解题思路:
S
1
=
a
1
S_1=a_1
S1=a1
S
2
=
a
1
+
a
2
S_2=a_1+a_2
S2=a1+a2
.
.
.
...
...
S
n
=
a
1
+
a
2
+
.
.
.
+
a
n
S_n=a_1+a_2+...+a_n
Sn=a1+a2+...+an
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
−
--------------------
−−−−−−−−−−−−−−−−−−−−
S
S
1
=
S
1
SS_1=S_1
SS1=S1
S
S
2
=
S
1
+
S
2
SS_2=S_1+S_2
SS2=S1+S2
.
.
.
...
...
S
S
n
=
S
1
+
S
2
+
.
.
.
+
S
n
SS_n=S_1+S_2+...+S_n
SSn=S1+S2+...+Sn
当修改ai为w时,Si~Sn都会发生变化,每个变化之后改变w-ai
SSn~SSi区间加上w-ai
到这里就可以直接利用树状数组存储S的值,进行区间修改,和区间查询即可,最后别忘了每次要更新ai的值
AC代码:
#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
ll n, m;
ll a[maxn], suma[maxn], sum1[maxn], sum2[maxn];
void update(ll i, ll k) {//树状数组的区间操作模板函数
ll x = i;
while (i <= n) {
sum1[i] += k;
sum2[i] += k * (x - 1);
i += lowbit(i);
}
}
ll getsum(ll i) {
ll res = 0, x = i;
while (i > 0) res += x * sum1[i] - sum2[i], i -= lowbit(i);
return res;
}
int main() {
IOS;
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++) {
suma[i] = suma[i - 1] + a[i];
update(i, suma[i] - suma[i - 1]);
}
string oper; ll x, y;
while (m--) {
cin >> oper;
if (oper == "Query") {
cin >> x;
cout << getsum(x) << endl;
}
else {
cin >> x >> y;
ll tmp = y - a[x];
a[x] = y;//更新值
update(x, tmp), update(n + 1, -tmp);
}
}
}