1. 程式人生 > 遊戲攻略 >《原神攻略》幻影心流第三日打法思路

《原神攻略》幻影心流第三日打法思路

樹狀陣列


講樹狀陣列前需要有個大前提----lowbit()函式

lowbit(x)是x的二進位制表示式中最低位的1所對應的值

就比如說,6的二進位制是110,所以lowbit(6)=2

在學樹狀陣列前,我們要學會lowbit()函式常用程式碼寫法:



下面我們學習用lowbit(x)來維護區間

大前提設節點編號為x,那麼該結點維護的區間和是( x-lowbit(x),x ]

假設二叉樹有編號有x={1、2、3、4、5、6、7、8},共8個結點//藉助二叉樹來分析

用陣列A[1]、A[2]......A[8]儲存,那麼各個結點維護區間和 的區間(c[i])為:

c1維護區間(1-lowbit(1),1]即(0,1]A1

本身

c2維護區間(2-lowbit(2),2]即(0,2]A1+A2

同理:c3維護(2,3]A3

c4維護(0,4]A1+A2+A3+A4

c5維護(4,5]A5

c6維護(4,6]A5+A6

c7維護(6,7]A7

c8維護(0,8]A1+A2+A3+A4+A5+A6+A7+A8

由此我們可以畫出區間維護圖為:

我們設C[i]代表子樹的葉結點權值之和:

C[2]=A[1]+A[2];

C[3]=A[3];

C[4]=A[1]+A[2]+A[3]+A[4];

C[5]=A[5];

C[6]=A[5]+A[6];

C[7]=A[7];

C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];

將C[i]陣列的結點序號轉化為二進位制 1=(001) C[1]=A[1];

2=(010) C[2]=A[1]+A[2];

3=(011) C[3]=A[3];

4=(100) C[4]=A[1]+A[2]+A[3]+A[4];

5=(101) C[5]=A[5];

6=(110) C[6]=A[5]+A[6];

7=(111) C[7]=A[7];

8=(1000) C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];

對照式子可以發現 C[i]=A[i-2^k+1]+A[i-2^k+2]+......A[i]; //區間和表示 (k為i的二進位制中從最低位到高位連續零的長度)

如驗證i=6,k=1。C[6]=A[6-2^1+1]+A[6-2^1+2]+..A[6] = A[5]+A[6]

lowbit(x) 就是取出x的最低位1,換言之lowbit(x)=2^k

那麼我們可以得到一個重要結論:

C[i]=A[i-2^k+1]+A[i-2^k+2]+......A[i];

C[i]=A[i-lowbit(i)+1]+A[i-lowbit(i)+2]+......A[i];



之後我們結合二叉樹性質來分析:

A[8]={1,2,0,1,3,0,2,1} //假定初值

C[i]表示儲存的區間和(附上一張圖)

由此我們可以推出四條重要性質:(最好結合圖例,將其背過)

(性質1)每個內部結點C[x]儲存以它為根的子樹中所有葉結點的和。

(性質2)每個內部結點C[x]的子結點個數等於lowbit(x)的值。

(性質3)除樹根以外,每個內部結點C[x]的父親結點是C[x+lowbit(x)]

(性質4)樹的深度為O(logN)


緊接著我們再來分析一下它的性質:

(性質1)每個內部結點C[x]儲存以它為根的子樹中所有葉結點的和。

這裡就會運用到樹狀陣列中一個重要的演算法:查詢字首和(這裡附上程式碼)

****當然,他還是有兩個大前提的:

大前提(1) . lowbit(x)運算(上文已講述)

大前提(2) . 樹狀陣列處理的下標為1..n的陣列,絕不能出現下標0的情況。因為lowbit(0)=0 陷入死迴圈

樣例:x=5,求C[5] //即C[5]字首和c1~c5之和

1迴圈: while(5>0) res=c[5]=a[5]=3 x=5-lowbit(5)=5-1=4 2迴圈: while(4>0) res=c[5]+c[4]=3+4=7 x=4-lowbit(4)=4-4=0 //迴圈結束,返回res=7


(性質3)除樹根以外,每個內部結點C[x]的父親結點是C[x+lowbit(x)]

這裡就會運用到另一個演算法:單點修改

樣例:由上圖n=8,x=5,y=10使a[5]+10區間修改過程:

迴圈1. while(5<=8) c[5]=3+10=13 x=5+lowbit(5)=5+1=6 //父編號

迴圈2. while(6<=8) c[6]=3+10=13 x=6+lowbit(6)=6+2=8 //父編號

迴圈3. while(8<=8) c[8]=10+10=20 x=8+lowbit(8)=16>n //迴圈結束

最後還剩一個區間和計算:sum(y)-sum(x-1)(此處不再多講)

完美撒花!