Appearance
线性建树
树上共有
cpp
void init(int n, vector<int> &a) {
this->n = n;
for (int i = 1; i <= n; i++) {
tr[i] += a[i];
int j = i + lowbit(i);
if (j <= n)
tr[j] += tr[i];
}
}还有一个更简单的
cpp
void init(int n, vector<int> &sum) {
this->n = n;
for (int i = 1; i <= n; i++) {
tr[i] += sum[i] - sum[i - lowbit(i)];
}
}树状数组倍增
对于
从最高位开始,若这一位的管辖区间的
空间复杂度:
cpp
int ask(int v) {
int now = 0;
for (int i = 20; i >= 0; i--) {
int cur = now + (1 << i);
if (cur > n)
continue;
if (tr[cur] <= v) {
now = cur;
v -= tr[now];
}
}
return now + 1;
}树状数组维护区间加、区间和:
区间和可差分为前缀和。
令
交换求和次序可得:
所以可以转换成在两个差分数组上的单点加和区间和,使用两个树状数组维护即可。
与线段树相比具有常数小、代码短的优势。洛谷【线段树 1】上述实现效率和码量都是递归线段树
维护不可差分信息
以区间
单点修改:
将
解决办法是,从后代更新到祖先,那么当更新到祖先时,后代就一定是正确的,所以每次将当前节点修改为
不难得到,
cpp
void update(int x, int v) {
a[x] = v;
for (; x <= n; x += lowbit(x)) {
tr[x] = a[x];
for (int y = 1; y < lowbit(x); y <<= 1)
tr[x] = max(tr[x], tr[x - y]);
}
}区间询问:
和树状数组倍增类似,假设询问区间
cpp
int query(int l, int r) {
int res = 0;
while (r >= l) {
res = max(res, a[r]);
--r;
for (; r - lowbit(r) >= l; r -= lowbit(r)) res = max(res, tr[r]);
}
return res;
}容易发现,可差分信息也可以通过这个求(但是没有必要)。实测洛谷【树状数组 1】上述
