有一种数组叫树状数组
树状数组,对于每一个点,它有一个管辖区域
具体是这样的:
(摘自BaiDu)
然后发现对于x,它所包含了x-lowbit(x)+1~x
这个lowbit(x)表示2^k(k为x二进制末尾连续0的个数)
这个lowbit怎么求呢?
lowbit(x)=x&-x
讲解一下树状数组各部分的作用:
change(x,y):表示把x~n这个区间的信息与y综合更新
getsum(x):表示得到1~x这个区间想要得到的答案
注意:
- 整篇博文数组都是管辖前缀的,后缀只要稍稍做个改动
- 树状数组可以维护区间和,区间最值,但这个区间没线段树灵活
模板:
1、lowbit
int lowbit(int x){
return x&-x;
}
2、修改,加法
void change(int x,int y){
for (;x<=n;x+=lowbit(x)) tree[x]+=y;
}
3、查询,加法
int getsum(int x){
int ans=0;
for (;x;x-=lowbit(x)) ans+=tree[x];
return ans;
}
4、修改,最值
void change(int x,int y){
for (;x<=n;x+=lowbit(x)) tree[x]=max(tree[x],y);
}
5、查询,最值
int getsum(int x){
int ans=0;
for (;x;x-=lowbit(x)) ans=max(ans,tree[x]);
return ans;
}
LuoGu树状数组模板1
Code:
var
c:array[0..1000000] of longint;
n,m,x,y,i:longint;
function lowbit(x:longint):longint;
begin
exit(x and -x);
end;
procedure change(x,y:longint);
begin
while x<=n do
begin
inc(c[x],y);
inc(x,lowbit(x));
end;
end;
function getsum(x:longint):longint;
begin
getsum:=0;
while x>0 do
begin
inc(getsum,c[x]);
dec(x,lowbit(x));
end;
end;
begin
readln(n,m);
for i:=1 to n do
begin
read(x);
change(i,x);
end;
for i:=1 to m do
begin
read(x);
if x=1 then
begin
readln(x,y);
change(x,y);
end else
begin
readln(x,y);
writeln(getsum(y)-getsum(x-1));
end;
end;
end.
LuoGu树状数组模板2
Code:
var
c:array[0..1000000] of longint;
n,m,x,y,z,last,i:longint;
function lowbit(x:longint):longint;
begin
exit(x and -x);
end;
procedure change(x,y:longint);
begin
while x<=n do
begin
inc(c[x],y);
inc(x,lowbit(x));
end;
end;
function getsum(x:longint):longint;
begin
getsum:=0;
while x>0 do
begin
inc(getsum,c[x]);
dec(x,lowbit(x));
end;
end;
begin
readln(n,m);
for i:=1 to n do
begin
read(x);
change(i,x-last);
last:=x;
end;
for i:=1 to m do
begin
read(x);
if x=1 then
begin
readln(x,y,z);
change(x,z);
change(y+1,-z);
end else
begin
readln(x);
writeln(getsum(x));
end;
end;
end.
Ps:LuoGu的两模板题的Code是博主一年前的老代码了,码风诡异,望谅解