[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));
		}
	}
}
posted @ 2021-02-23 11:14  _dwt  阅读(48)  评论(0)    收藏  举报