二叉索引樹 (binary indexed tree,bit)
動態連續和查詢問題,給定乙個n個元素的陣列a1,a
2,..........
an。支援以下兩種操作
1.add(x,d)操作:讓a
x增加d。
2.query(l,r):計算al+a
l+1+.......+ar。
在學習二叉索引樹之前,需要先介紹lowbit.
對於正整數x,我們定義lowbit(x)為x的二進位制表示式中最右邊的1所對應的值。例如,38288的二進位制是:1001010110010000,所以lowbit(x) = 16(二進位制為10 000)。在程式實現中,lowbit(x) = x & (-x)。 因為計算機裡的整數採用補碼便是,因此-x實際上是x按位取反,末尾加1以後的結果。如下圖
兩者按位取「與」之後,前面部分全部為零,之後lowbit保持不變(都是第五位)。
下圖是一棵典型的bit,由十五個節點組成,編號為1 - 15.
灰色結點是bit中的結點(白色長條的含義稍後敘述),每一層結點的lowbit相同,而且lowbit越大,越靠近根。圖中的虛線是bit中的邊。
編號為0的點是虛擬結點,他並不是樹的一部分,但是他的存在可以讓
演算法理解起來更容易一些。
對於結點i,如果它是左子結點,那麼父結點的編號是i+lowbit(i)。如果它是右子結點,那麼父結點的編號是i-lowbit(i)。搞清楚樹的結構之後,構造乙個輔助陣列c,其中c[i]=a[i-lowbit(i)+1]+a[i-lowbit(i)+2]+....+a[i]。換句話說,c的每個元素都是a陣列中的一段連續和。到底是那一段呢?在bit中,每個灰色結點i都屬於乙個以它自身結尾的水平長條(對於lowbit=1的那些點,長條就是他本身),這個長條中數之和就是c[i]。其中
c[i] = a
i-lowbit(x)
+1 + a
i-lowbit(x)+2
+...+ai;
所以,有了c陣列,就可以計算si 了,其實只要節點i往左上「爬」就可以了,如下圖
所以相應**如下:
int sum(int x)
return ans;
}
而如果要修改ai,則應該順著i點往右走,為什麼?因為i點的改變會引起其父親節點的改變。如下圖
所對應的**為:
void add(int x,int d)
}
所以到最後我們就可以計算a1+a2+...+ai,並且修改某ai的值。
下面是一道練習題;
codevs p1080;
ac**如下:
/*
題目:p1080 線段樹練習
*/#includetypedef long long ll;
ll c[100000+10],n,m;
inline int lowbit(int x)
int sum(int x)
return res;
}void add(int x,int a)
}int main()
scanf("%d",&m);
while(m--)
return 0;
}
樹狀陣列(二叉索引樹)
樹狀陣列的原理介紹可見劉汝佳 演算法競賽入門經典 訓練指南 194頁,講的非常好 簡單自己對樹狀陣列的基本理解 我們原先不是把陣列看成一排嗎,但現在不是了,我們用乙個類似二叉樹的結構來儲存資料,存到c當中去,好好研究劉汝佳所畫的圖。下面說明基本應用 對於乙個n元素的陣列a n 可執行如下操作 add...
二叉索引樹(樹狀陣列)
二叉索引樹 binary indexed tree 又叫樹狀陣列,主要是用於解決動態連續和查詢問題。給定乙個n個元素的陣列a1,a2,an,你的任務是設計乙個資料結構,支援以下兩種操作。對於正整數x,我們 定義lowbit x 為想的二進位制表示式中最右邊所對應的值。比如由38288的二進位制是10...
BIT二叉索引樹(樹狀陣列)
powered by phantom lsh將上面的求連續和問題稍微改進一下,現在需要支援一種新的操作 add x d 即把a x 增加d。這樣一來,如果通過字首和的方式計算就不能簡化計算了,因為每次修改乙個元素都要修改所有在它後面的字首和。有什麼解決辦法呢?我們需要用一種新的資料結構 bit二叉索...