树状数组
树状数组的本质是将前缀进行拆分维护,\(i\)号节点维护的是原序列上\([i-lowbit(i)+1,i]\)这段区间的信息。
\(lowbit(x)\)表示\(x\)这个数在2进制下从低到高第一个非零位在十进制下的,例如\(lowbit(7)=1,lowbit(8)=8\)。
根据计算机补码的性质可得\(lowbit(x)=x\)&\((-x)\)。
单点修改:其实就是一个不断找到管辖自己区间的过程,方法就是不断给i自己加上\(lowbit(i)\)跳到下一个管辖自己的区间。
前缀查询:就是把前缀进行拆分,方法就是不断给\(i\)自己扣除\(lowbit(i)\)跳到下一个前缀。
这两个操作的复杂度都是单次\(O(log\) \(n)\)的。
\(code\):
void update(int t,int v)
{
while(t<=n)
{
tree[t]+=v;
t+=lowbit(t);
}
}
int query(int t)
{
int sum=0;
while(t)
{
sum+=tree[t];
t-=lowbit(t);
}
return sum;
}
......
update(x,y);//单点修改,x加上y
query(y)-query(x-1)//区间查询,x到y的和
树状数组还可求逆序对