[LuoguP3368]树状数组2(单点查询&&区间修改)
Link:https://www.luogu.com.cn/problem/P3368
description: 实现一个支持动态区间修改(区间内的每个数增加常量), 和单点查询的数据结构.
solution:
Consider the difference, let \(a[0] = 0\), \(a[k]=\Sigma_{i=1}^{k}(a[i]-a[i-1])\)
这样单点查询转化为区间前缀和查询,
同时带来方便:区间修改
只要将树状数组维护的 \(t[l], t[l+lowbit(l)]\),..., \(add(k), s.t. a[l,N]+k\);
同时对 \(t[r+1], t[r+1+lowbit(r+1)]\),..., \(add(-k), s.t. a[l,r]+k\).
注意: \((i+lobit)是i的parent节点\).每次修改一个节点必须连带着修改他的所有祖先节点.
code:
#include<cstdio>
inline int read() {
int ch = getchar(),tot=0, f = 1;
while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
while (ch <= '9' && ch >= '0') tot = (tot << 1) + (tot << 3) + ch - '0', ch = getchar();
return f * tot;
}
int N, M;
const int maxn = 500005;
int d[maxn], t[maxn];
inline int lowbit(const int& x) { return x & -x; }
inline void pre_calc() {
for (int i = 1; i <= N; ++i)
for (int j = i - lowbit(i) + 1; j <= i; ++j)
t[i] += d[j];
}
inline int query(const int& id) {
int sum = 0;
for (int i = id; i; i -= lowbit(i))sum += t[i];
return sum;
}
inline void add(const int& l, const int& r, const int& k) {
for (int i = l; i <= N; i += lowbit(i))t[i] += k;
if (r + 1 <= N)for (int i = r + 1; i <= N; i += lowbit(i))t[i] -= k;
}
int main() {
N = read(), M = read();
int last = 0;
for (int i = 1; i <= N; ++i) {
int cur = read();
d[i] = cur - last;
last = cur; //diff
}
pre_calc();
while (M--) {
int op = read();
if (op == 1) {
int x, y, k;
x = read();
y = read();
k = read();
add(x, y, k);
}
else {
int id = read();
printf("%d\n", query(id));
}
}
}