树状数组还可以用来求区间异或和等与加法相同性质的操作
单点更新, 区间查询
相比于线段树, 好写的多
下标从1开始, sum(k)返回区间[1, k]的值, update将位置p的值+x
复杂度都是
O(logn)
O
(
l
o
g
n
)
int bit[maxn], n;
inline int lowbit(int x) { return x&(-x); }
inline void init(int n) { memset(bit, 0, sizeof(int) * (n+1)); }
int sum(int k)
{
return k<=0 ? 0 : bit[k] + sum(k-lowbit(k));
}
void update(int p, int x)
{
for( ; p<=n; p+=lowbit(p)) bit[p] += x;
}
inline int query(int l, int r) { return sum(r) - sum(l-1); }
区间修改, 单点查询
核心代码一模一样, 只是调用函数时候不同
int bit[maxn], n;
inline int lowbit(int x) { return x&(-x); }
inline void init(int n) { memset(bit, 0, sizeof(int) * (n+1)); }
int sum(int k)
{
return k<=0 ? 0 : bit[k] + sum(k-lowbit(k));
}
void update(int p, int x)
{
for( ; p<=n; p+=lowbit(p)) bit[p] += x;
}
//将区间[l, r]加v
update(l, v);
update(r+1, -v);
//查询点pos
sum(pos);
区间修改, 区间更新
利用一个二维树状数组实现区间更新, 复杂度都是 O(logn) O ( l o g n )
int bit0[MAXN], bit1[MAXN];
int n;
inline int lowbit(int x) { return x&(-x); }
int sum(int bit[], int k)
{
return k<=0 ? 0 : bit[k] + sum(bit, k - lowbit(k));
}
void update(int bit[], int i, int x)
{
for( ; i<=n; i+=lowbit(i)) bit[i] += x;
}
inline int query(int l, int r)
{
return sum(bit0, r) - sum(bit0, l-1) + sum(bit1, r) * r - sum(bit1, l-1) * (l-1);
}
inline void update(int l, int r, int x)
{
update(bit0, l, -x*(l-1));
update(bit0, r+1, x*r);
update(bit1, l, x);
update(bit1, r+1, -x);
}
二维树状数组
单点更新, 区间查询
const int maxn = 2500 + 10, inf = 0x3f3f3f3f;
typedef unsigned long long ull;
ull bit[maxn][maxn];
int n;
inline int lowbit(int x) { return x&(-x); }
ull sum(int x, int y)
{
ull s = 0;
for(int i=x; i>0; i-=lowbit(i))
for(int j=y; j>0; j-=lowbit(j))
s += bit[i][j];
return s;
}
void add(int x, int y, int v)
{
for(int i=x; i<=maxn; i+=lowbit(i))
for(int j=y; j<=maxn; j+=lowbit(j))
bit[i][j] += v;
}
//查询(x1, y1), (x2, y2)
sum(x2, y2)-sum(x2, y1-1)-sum(x1-1 ,y2)+sum(x1-1, y1-1);
//修改(x,y)
add(x, y, v);
区间修改, 单点查询
//查询(x, y)
sum(x, y);
//改变(x1, y1)(x2, y2)全部加v
add(x1, y1, v);
add(x1, y2+1, -v);
add(x2+1, y1, -v);
add(x2+1, y2+1, v);