樹狀陣列真是乙個好東西啊qaq,**短且好寫。
首先它的原理是半二叉樹,差不多可以這麼叫吧,,,
比較重要的low
bitlowbit
lowbit
操作:
int
lowbit
(int x)
x&(-x),當x為0時結果為0;建樹時 c[ix為奇數時,結果為1;
x為偶數時,結果為x中2的最大次方的因子。
]=a[
i−2k
+1]+
a[i−
2k+2
]+..
.+a[
i]c[i]=a[i-2^k+1]+a[i-2^k+2]+...+a[i]
c[i]=a
[i−2
k+1]
+a[i
−2k+
2]+.
..+a
[i]求和時 sum
[i]=
c[i]
+c[i
−2k1
]+c[
(i−2
k1)−
2k2]
...;
sum[i]=c[i]+c[i-2^]+c[(i-2^)-2^]...;
sum[i]
=c[i
]+c[
i−2k
1]+c
[(i−
2k1)
−2k2
]...
;那麼就可以建樹了
int n;
int a[n]
,c[n]
;//對應原陣列和樹狀陣列
intlowbit
(int x)
void
updata
(int i,
int k)
}int
getsum
(int i)
return res;
}int
main
(int argc,
char
const
*ar**)
return0;
}
這樣子就可以進行簡單的單點更新,區間求和。
要進行區間更新只需要用差分陣列來建樹即可,總體模板不變,只需要更改建樹的操作即可
經過一系列的推導:
在更新(l,
r)(l,r)
(l,r
)區間時只需要更新c[l
]+k,
c[r+
1]−k
c[l]+k,c[r+1]-k
c[l]+k
,c[r
+1]−
k即可。
注意此時查詢的get
sumgetsum
getsum
函式返回的值為a[i
]a[i]
a[i]
位置上的值而非字首和的值。
for
(int i =
1; i <= n; i++
)
這個就比較麻煩,同樣是使用差分陣列來維護,但是需要更改upd
ateupdate
update
函式及get
sumgetsum
getsum
函式。經過一系列推導:
只需要維護倆個陣列sum
1sum1
sum1
及s um
2sum2
sum2
即可。
int n,m;
int a[
50005]=
;int sum1[
50005];
//(d[1] + d[2] + ... + d[n])
int sum2[
50005];
//(1*d[1] + 2*d[2] + ... + n*d[n])
intlowbit
(int x)
void
updata
(int i,
int k)
}int
getsum
(int i)
return res;
}int
main()
//[x,y]區間內加上k
updata
(x,k)
;//a[x] - a[x-1]增加k
updata
(y+1
,-k)
;//a[y+1] - a[y]減少k
//求[x,y]區間和
int sum =
getsum
(y)-
getsum
(x-1);
return0;
}
好了這樣子乙個logn的資料結果就學完了,是不是覺得特別輕鬆呢hhhhhh
本菜雞用了好幾個小時呢qaq
參考部落格:
樹狀陣列學習
之前寫的題也遇到過用樹狀陣列,當時都是現查現學,而且總是搞不懂,今天又遇到了一道求區間和的題,不管最後是不是用樹狀陣列可以a,但是既然已經想到了這,就打算好好學習一下。可惜之前查到的資料都沒有儲存記錄,所以又重新查了些資料,彙總學習如下 文末附上樹狀陣列的詳細 樹狀陣列主要用到的操作 int low...
樹狀陣列學習
我覺得,樹狀陣列挺重要的就是那個 lower x x x 我說說我的理解吧。每乙個正整數都可以拆分成 2 的某些冪之和,例如 15 8 4 2 1 6 4 2 7 4 2 1 感覺可以解釋lca的倍增跳 那麼轉換成二進位制是什麼樣的呢?15 十進位制 1111 1000 100 10 1 6 十進位...
樹狀陣列學習
樹狀陣列與並查集類似,是一種資料結構,它可以用來維護字首和問題 不過,利用字首和和查分的思想,我們也可以用樹狀陣列解決區間問題 與線段樹不同,目前我暫且認為線段樹解決最值問題,而樹狀陣列解決求和問題 樹狀陣列原理建立在二叉樹上 利用lowbit運算實現向根節點儲存的原理 介紹lowbit的程式實現只...