【学习笔记】树状数组

有一种数组叫树状数组
树状数组,对于每一个点,它有一个管辖区域
具体是这样的:
这里写图片描述(摘自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是博主一年前的老代码了,码风诡异,望谅解

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/81487981