模板 樹狀陣列

2022-04-30 01:03:15 字數 3327 閱讀 4199

先膜黑科技講義 - magolor orz

設lowbit(x)表示的是把x的二進位制只留下最低一位的1,然後lowbit(x)=x&(-x) (我也不知道為什麼)

設c[x]表示從i往前一共lowbit(x)個數的和,那麼x-lowbit(x)就是c[x]表示的範圍的前乙個數。

然後可以得到c[x]=c[x-lowbit(x)+lowbit(x)>>1]+c[x-lowbit(x)+lowbit(x)>>1+lowbit(x)>>2]+c[x-lowbit(x)+lowbit(x)>>1+lowbit(x)>>2+lowbit(x)>>3]....+c[x-1]+a[x]。

也就是說,如果將這個關係做成乙個樹,x的父親就是x+lowbit(x)(觀察一下上面的式子,很容易發現每一項都滿足)

要詢問1到x的和的話,只要一直加c[x],然後讓x-=lowbit(x)直到x=0就好了

然後要修改乙個點x的話,就一直往上修改它的父親直到x>n就可以了。

也就是說,最基本的樹狀陣列支援的是單點修改和字首和查詢,然後字首和可以很容易地做成區間和(端點減一減)。

luogu3374

1 #include2 #include3 #include4

#define lowbit(x) ((x)&(-(x)))

5#define ll long long int

6const

int maxn=500050;7

8 inline int

rd()

11while(c>='

0'&&c<='

9') x=x*10+c-'

0',c=getchar();

12return x*neg;13}

1415

intn,m;

16ll c[maxn];

1718 inline void add(int x,int

y)21 inline ll query(int

x)24

25int

main()

34 }

view code

也可以支援區間修改和單點查詢,只要做乙個差分,區間修改就變成了兩個端點的修改,單點查詢就變成了字首和查詢。

luogu3368

1 #include2 #include3 #include4

#define lowbit(x) ((x)&(-(x)))

5#define ll long long int

6const

int maxn=500050;7

8 inline int

rd()

11while(c>='

0'&&c<='

9') x=x*10+c-'

0',c=getchar();

12return x*neg;13}

1415

intn,m;

16ll c[maxn];

1718 inline void add(int x,int

y)21 inline ll query(int

x)24

25int

main();

31for(i=1;i<=m;i++)

37else printf("

%lld\n

",query(b));38}

39 }

view code

區間修改和區間查詢也是可以支援的,然後我選擇線段樹......

樹狀陣列寫起來真方便,suki

$$前n項和\sum_^=\sum_^^}(差分陣列)=\sum_^=(n+1)\sum_^-\sum_^$$

這樣的話,只要同時維護d[i]和i*d[i],就可以做到區間修改和區間查詢了。

luogu3372

1 #include2 #include3 #include4 #include5 #include6 #include7 #include8 #include9 #include

10#define pa pair11

#define lowb(x) ((x)&(-(x)))

12#define rep(i,n0,n) for(i=n0;i<=n;i++)

13#define per(i,n0,n) for(i=n;i>=n0;i--)

14#define max(a,b) ((a>b)?a:b)

15#define min(a,b) ((a16

#define clr(a,x) memset(a,x,sizeof(a))

17#define rei register int

18using

namespace

std;

19 typedef long

long

ll;20

const

int maxn=100010;21

22ll rd()

25while(c>='

0'&&c<='

9') x=x*10+c-'

0',c=getchar();

26return x*neg;27}

2829

intn,m;

30ll tr[maxn],itr[maxn];

3132 inline void add(int

x,ll y)37}

38 inline ll query(int

x)return

re;43}44

45int

main()for(i=1;i<=m;i++)else57}

58return0;

59 }

view code

二維的話也是可以做的,就相當於每跳到乙個x都跳一遍y的lowbit,而且可以支援區間修改和區間查詢

單點修改區間查詢不多說,來說說區間修改和查詢

仿照一維的形式,我們先得到差分陣列

因為差分陣列的字首和就是原來那個點的值,所以能得到$d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]$

所以如果是(x1,y1,x2,y2)區間加的話,就是給(x1,y1),(x2+1,y2+1)加,給(x1,y2+1),(x2+1,y1)減(手畫一下)

然後是查詢,也是有$(x1,y1,x2,y2)=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]$

然後有$$s[x][y]=\sum\limits_^^^^}}}$$

$$=\sum\limits_^^^}}$$

$$=\sum\limits_^^}$$

於是二維樹狀陣列維護d,id,jd和ijd就行了

高階用法以後慢慢填

樹狀陣列模板

假設有一列數 1 i n 支援如下兩種操作 1.將ai的值加d。2.輸出ai ai 1 aj 1 i j n 樹狀陣列是一種特殊的資料結構,這種資料結構的時空複雜度和線段樹相似,但是它的係數要小得多 hdu 1166 敵兵布陣 題目 a國在海岸線沿直線布置了n個工兵營地。由於採取了某種先進的監測手段...

樹狀陣列模板

已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數數加上x 2.求出某乙個數的和 這種水水的樹狀陣列,博主就不做介紹,直接上 希望大家可以多多捧場!include include include include include include include include include ...

樹狀陣列模板

樹狀陣列 binary indexed tree bit fenwick tree 是乙個查詢和修改複雜度都為log n 的資料結構。主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改乙個元素的值 經過簡單修改可以在log n 的複雜度下進行範圍修改,但是這時只能查詢其中乙個元素的值。一,改點...