樹狀陣列基礎總結

2021-09-18 06:01:04 字數 3781 閱讀 3450

入門博文:

共同點:同時乙個節點維護多個葉子節點的資訊

不同點:線段樹節點採用二分的規則,而樹狀陣列節點利用了bit位的性質來鎖定管理的葉子節點,且樹狀陣列只能直接查詢1~i區間的資訊,而線段樹可以直接查詢[l,

r]

[l,r]

[l,r

] 區間資訊,

樹狀陣列可以解決問題的思路推廣到線段樹都可以用線段樹解決。不過樹狀陣列**量是真的小!

樹狀陣列核心函式:

這樣的**要求其葉子節點必須從1開始(因為此處維護的都是1~i的資訊,可以改下**使維護0到i的資訊,不過**就不簡潔了)

int

lowbit

(ll val)

intgetsum

(ll k)

//遍歷1~k區間的管理節點。

return ans;

}void

modify

(ll k,ll val)

//向上更新管理葉子節點k的節點資訊。

}

洛谷模板題,改點查段:

#include

#define mset(a,b) memset(a,b,sizeof(a))

using

namespace std;

typedef

long

long ll;

const

int maxn=

5e5+

100;

ll qwe[maxn]

,n,q;

intlowbit

(ll val)

intgetsum

(ll k)

return ans;

}int

modify

(ll k,ll val)

}int

main()

while

(q--

)else

}return0;

}

比如:lis(最長遞增子串行),求逆序對,改點查段,改段查點的問題都可以用樹狀陣列解決。

lis(最長遞增子串行)思想:f[i

]f[i]

f[i]

表示當前以值 i

ii 為遞增子串行末尾的序列最長長度。每個葉子 i

ii 記錄當前f[i

]f[i]

f[i]

, 最大值,那麼用樹狀陣列節點維護其葉子節點的最大值即可。如果該此時序列中數字值為val,那麼f[v

al]=

max(

f[i]

)i∈[

1,va

l]+1

=get

max(

i)+1

f[val]=max(f[i])_+1 =\ \ ~getmax(i)+1

f[val]

=max

(f[i

])i∈

[1,v

al]​

+1=g

etma

x(i)

+1ps:有時候需要離散化,所以還是二分求lis比較好用

求逆序對思想:

每個葉子 i

ii 記錄當前值i的出現次數,那麼用樹狀陣列節點維護其管理的葉子節點出現次數和即可,假設當前第k個數其值為val,那麼前面大於val的個數=k−1

−get

sum(

val)

k-1-getsum(val)

k−1−ge

tsum

(val

)

#include

#define mset(a,b) memset(a,b,sizeof(a))

using

namespace std;

typedef

long

long ll;

const

int maxn=

5e5+

100;

int tot,n;

int unq[maxn]

,qwe[maxn]

,bt[maxn]

;int

getind

(int val)

intlowbit

(int val)

ll getsum

(int k)

return ans;

}void

modify

(int k)

//k葉子+1

}int

main()

cout<}

改段查點:

修改:將區間 $[l,r] $ 的每個數加val,查詢:求點k處的值

假設原陣列為num

[]

numnu

m[],我們用d[]

dd[

] 記錄相鄰元素的差值,比如d[i

]=nu

m[i]

−num

[i−1

]d[i]=num[i]-num[i-1]

d[i]=n

um[i

]−nu

m[i−

1],且我們讓 d[1

]=nu

m[1]

d[1]=num[1]

d[1]=n

um[1

] ,那麼num

[i]=

d[1]

+d[2

]...

..+d

[i

]num[i]=d[1]+d[2].....+d[i]

num[i]

=d[1

]+d[

2]..

...+

d[i]

至於修改操作,我們只需將d[l

]d[l]

d[l]

加上v al

valva

l,d[r+

1]

d[r+1]

d[r+1]

減去v al

valva

l即可,

我們維護d陣列即可。

洛谷模板:

**:

// luogu-judger-enable-o2

#include

#define mset(a,b) memset(a,b,sizeof(a))

using

namespace std;

typedef

long

long ll;

const

int maxn=

5e5+

100;

ll qwe[maxn]

,n,q;

intlowbit

(ll val)

intgetsum

(ll k)

return ans;

}void

modify

(ll k,ll val)

}ll va[maxn]

;int

main()

modify(1

,va[1]

);for(

int i=

2;i<=n;

++i)

modify

(i,va[i]

-va[i-1]

);while

(q--

)else

}return0;

}

樹狀陣列總結

樹狀陣列的基本知識已經被各種大牛和菜鳥講到爛了,我就不多說了,下面給出基本操作的 假定原陣列為a 1.n 樹狀陣列b 1.n 考慮靈活性的需要,使用int a傳陣列。define lowbit x x x int sum int a,int x void update int a,int x,int...

樹狀陣列總結

樹狀陣列是對乙個陣列改變某個元素和求和比較實用的資料結構。兩中操作都是o logn 在解題過程中,我們有時需要維護乙個陣列的字首和s i a 1 a 2 a i 但是不難發現,如果我們修改了任意乙個a i s i s i 1 s n 都會發生變化。可以說,每次修改a i 後,調整字首和s在最壞情況下...

樹狀陣列總結

今天學習了一下樹狀陣列,做乙個簡單總結。樹狀陣列可分為兩種操作,1 修改單個點,統計區間和 一般為 向上修改 update1 向下統計 sum1 2 修改區間,統計單個點 一般為向下修改 update2 向上統計 sum2 主要模板如下 int c n int lowbit int x 用於確定區間...