树状数组
操作
以下代码为树状数组最常用的几个操作
1. lowbit\mathrm{lowbit}lowbit
function lowbit(x:longint):int64;
Begin
exit(x and (-x));
end;
2. 单点修改
procedure replace(x,y:int64);
Var i:int64;
Begin
i:=x;
interim[x]:=y;
while i<=n do
Begin
tree[i]:=y;
i:=i+lowbit(i);
end;
end;
3. 区间查询
function get_summation(x:longint):int64;
Var i:int64;
Begin
get_summation:=0;
i:=x;
while i>0 do
Begin
get_summation:=get_summation+tree[i];
i:=i-lowbit(i);
end;
exit(get_summation);
end;
4.区间极值
function get_maximum(x,y:int64):int64;
Var i:int64;
Begin
get_maximum:=0;
i:=y;
while i>=x do
Begin
get_maximum:=max(interim[i],get_maximum);
i:=i-1;
while i-lowbit(i)>=x do
Begin
get_maximum:=max(tree[i],get_maximum);
i:=i-lowbit(i);
end;
end;
exit(get_maximum);
end;
以及……
区间修改可以树上差分。
概念
树状数组与线段树相似,效率上要比线段树高,但适用性却不如线段树。
定义一个数组TreeTreeTree表示子树的叶子结点的权值之和,这样可以发现到:
Tree1=a1Tree_1 = a_1Tree1=a1
Tree2=a1+a2Tree_2 = a_1 + a_2Tree2=a1+a2
Tree3=a3Tree_3 = a_3Tree3=a3
Tree4=a1+a2+a3+a4Tree_4 = a_1 + a_2 + a_3 + a_4Tree4=a1+a2+a3+a4
Tree5=a5Tree_5 = a_5Tree5=a5
Tree6=a5+a6Tree_6 = a_5 + a_6Tree6=a5+a6
Tree7=a7Tree_7 = a_7Tree7=a7
Tree8=a1+a2+a3+a4+a5+a6+a7+a8Tree_8 = a_1 + a_2 + a_3 + a_4 + a_5 + a_6 + a_7 + a_8Tree8=a1+a2+a3+a4+a5+a6+a7+a8
⋯\cdots⋯
经过观察可以得出Treei=ai−2k+1+ai−2k+2+⋯+aiTree_i = a_{i-2^k+1} + a_{i-2^k+2} + \cdots + a_iTreei=ai−2k+1+ai−2k+2+⋯+ai
lowbit\mathrm {lowbit}lowbit 函数的意义是取为 xxx 的二进制表达式中最低位的1所对应的值
树状数组本就是对于二进制的理解&运用,利用 lowbit\mathrm {lowbit}lowbit 我们可以快速遍历整棵树。
于是乎,树状数组还可以解决各种关于区间の问题。