树状数组 进阶篇:区间修改,区间查询
单点更新,区间查询
我们知道,树状数组最基本的功能是 单点更新,区间查询
代码如下:
int lowbit(int x) { return x & (-x); } void add(int x, int val) { while (x <= n) { tree[x] += val; x += lowbit(x); } } int ask(int x) { int res = 0; while (x) { res += tree[x]; x -= lowbit(x); } return res; }
区间更新,单点查询
通过 “单点更新,区间查询” 功能+差分的思想,我们实现了: 区间更新,单点查询
,所以,以c[i] 建立树状数组,
因为
所以我们想让区间 每一个a[i] 都加上x的话,我们只需要
进入我们今天的主题 :区间更新,区间查询
我们知道数组a[i]的差分数组 c[i] 满足:
那么
于是我们可以用2个树状数组,分别维护 和,数组名分别叫tree1,tree2
区间 的sum和就等于
如果怕询问 等情况,可以第二个树状数组tree2维护,根据差分数组的思想,并不影响结果。
代码:
long long tree1[maxn]; long long tree2[maxn]; long long ask(long long *tree, long long x) { long long sum = 0; for (; x; x -= (x & -x)) { sum += tree[x]; sum %= mod; } return sum; } void add(long long *tree, long long x, long long y) { for (; x <= n; x += (x & -x)) { tree[x] += y; tree[x] %= mod; } } ll query(ll l, ll r) { long long ans = 0; ans = ( (r + 1) * ask(tree1, r) - ask(tree2, r) ) -( l * ask(tree1, l - 1) - ask(tree2, l - 1) ); return ans; } void op(ll l, ll r , ll x) { add(tree1, l, x); add(tree1, r + 1, -x); add(tree2, l, l * x); add(tree2, r + 1, -(r + 1) * x); }