单点加值,区间求和
这个是最基础的树状数组的用法了。初始值是Init之后一个一个Add上去的。
struct BinaryIndexTree {
static const int MAXN = 500000 + 5;
int n;
int sm[MAXN];
void Add(int x, int v) {
for(int i = x; i <= n; i += i & (-i))
sm[i] += v;
}
ll Sum(int x) {
ll res = 0;
for(int i = x; i; i -= i & (-i))
res += sm[i];
return res;
}
void Init(int _n) {
n = _n;
memset(sm, 0, sizeof(sm[0]) * (n + 1));
}
} bit;
已通过:
https://www.luogu.com.cn/problem/P3374
单点改值,区间求和
额外记录一个va数组,然后每次比对这次要“加”的值是多少,套用单点加值。
struct BinaryIndexTree {
static const int MAXN = 500000 + 5;
int n;
int va[MAXN];
int sm[MAXN];
void Add(int x, int v) {
for(int i = x; i <= n; i += i & (-i))
sm[i] += v;
}
ll Sum(int x) {
ll res = 0;
for(int i = x; i; i -= i & (-i))
res += sm[i];
return res;
}
void Init(int _n) {
n = _n;
memset(va, 0, sizeof(va[0]) * (n + 1));
memset(sm, 0, sizeof(sm[0]) * (n + 1));
}
void Modify(int x, int v) {
int d = v - va[x];
Add(x, d);
va[x] = v;
}
} bit;
二维偏序
namespace BinaryIndexTree {
const int MAXN = 200000 + 5;
int n;
int nn;
int a[MAXN];
int aa[MAXN];
int bit[MAXN];
void Add(int x, int v) {
for(int i = x; i <= nn; i += i & (-i))
bit[i] += v;
}
ll Sum(int x) {
ll res = 0;
for(int i = x; i; i -= i & (-i))
res += bit[i];
return res;
}
void Init1() {
n = 0;
nn = 0;
}
void Insert(int v) {
a[++n] = v;
aa[++nn] = v;
}
void Init2() {
sort(aa + 1, aa + 1 + nn);
nn = unique(aa + 1, aa + 1 + nn) - (aa + 1);
memset(bit, 0, sizeof(bit[0]) * (nn + 1));
for(int i = 1; i <= n; ++i) {
a[i] = lower_bound(aa + 1, aa + 1 + nn, a[i]) - aa;
Add(a[i], 1);
}
}
}
区间修改区间求和
设差分数组 (d_i=a_i-a_{i-1}) ,显然有 (a_i=sumlimits_{j=1}^i d_j) ,那么 (Sum(x)=sumlimits_{i=1}^x a_i=sumlimits_{i=1}^x sumlimits_{j=1}^i d_j = sumlimits_{i=1}^x (x-i+1)*d_i=(x+1)sumlimits_{i=1}^xd_i - sumlimits_{i=1}^x i*d_i) 。
struct BinaryIndexTree {
// const int MAXN = 3e5 + 5;
int n;
ll d1[MAXN], d2[MAXN];
void Add(int x, int v) {
for(int i = x; i <= n; i += i & (-i)) d1[i] += v, d2[i] += 1LL * x * v;
}
ll Sum(int x) {
ll res = 0;
for(int i = x; i; i -= i & (-i)) res += 1LL * (x + 1) * d1[i] - d2[i];
return res;
}
int RangeAdd(int l, int r, int v) {
Add(l, v), Add(r + 1, -v);
}
ll RangeSum(int l, int r) {
return Sum(r) - Sum(l - 1);
}
void Init(int _n) {
n = _n;
memset(d1, 0, sizeof(d1[0]) * (n + 1));
memset(d2, 0, sizeof(d2[0]) * (n + 1));
}
} bit;