樹狀陣列求區間最值

2022-05-15 04:25:18 字數 3989 閱讀 8271

樹狀陣列(binary index tree)利用二進位制的一些性質巧妙的劃分區間,是一種程式設計,時間和空間上都十分理想的求區間和的演算法,同樣我們可以利用樹狀陣列優美的區間劃分方法來求乙個序列的最值

約定以 num  表示原陣列, 以 idx 表示索引陣列, lowbit(x)=x&(-x) 

樹狀陣列求和時通過構造陣列 idx 使 idx[k]=sum(num[tk]), tk [k-lowbit(k)+1,k], 使用同樣的方法構造最值索引陣列:

以最大值為例, 先討論詢問過程中不對陣列做任何修改的情況, 用 idx[k] 記錄 [k-lowbit(k)+1,k] 區間內的最大值, 可以仿照求和時的方法得到:12

3456

7voidinit(intn)

}

}

這種方法在每次呼叫該函式前都必須對陣列進行初始化, 這樣對於資料範圍比較大的時候不是很優美, 這樣我們可以改為:12

3456

78voidinit(intn)

}

}

這樣, 在更新到第k個數時, 所有 t(t然後再來看查詢的問題, 對於區間 [l,r] 把該區間轉化為多個的小區間再進行求最值, 方法是從後往前對每乙個索引數的範圍進行判斷, 如在進行到第k項時,該數控制的範圍是 [k-lowbit(k)+1,k], 如果k-lowbit(k)+1在所求的範圍內的話則將該區間的最值加入最值的判斷,然後轉至地k-lowbit(k),否則的話就只對第k個數進行最值判斷,然後轉至k-1,具體實現如下:12

3456

78910

11intquery(intl,intr)

}

returnans;

}

該查詢的複雜度為log(n)

st演算法的複雜度 o(nlog(n)) / o(1) , 線段樹為 o(nlog(n)) / (log(n)),樹狀陣列 o(空間複雜度 st 為 o(nlog(n)), 線段樹 o(n),常數較大 , 樹狀陣列是 o(n)

程式設計上 st 和 樹狀陣列 都比較容易實現,線段樹**較長

另外線段樹靈活性較大

pku 3264 題:

st    memory: 6372k  time: 1250ms  964b

bit  memory: 716k  time: 1282ms  933b

segtree  未測,要比st更大

然後我們可以進一步擴充套件到邊查詢邊修改的情況

每次直接去更新父親節點自然是不行的, 為了維護索引陣列的正確性,我們在對每個父親節點進行更新時都要查詢他的所有兒子節點,在其中取最優值, 得到**如下:12

3456

789voidmodify(intp,intv,intn)

}

}

複雜度為 o(log^2(n)),  hdu 1754  i hate it  437ms  1776k

另外,該方法還有乙個減枝, 很容易想到,在求最大值時,當某個值更新的值大於原值的時候是沒有必要再去查詢兒子節點的,所以內部迴圈可加乙個判斷來判定是否需要掃瞄兒子節點,可能是資料問題,該題時間並沒有大的變化

樹狀陣列(binary index tree)利用二進位制的一些性質巧妙的劃分區間,是一種程式設計,時間和空間上都十分理想的求區間和的演算法,同樣我們可以利用樹狀陣列優美的區間劃分方法來求乙個序列的最值

約定以 num  表示原陣列, 以 idx 表示索引陣列, lowbit(x)=x&(-x) 

樹狀陣列求和時通過構造陣列 idx 使 idx[k]=sum(num[tk]), tk [k-lowbit(k)+1,k], 使用同樣的方法構造最值索引陣列:

以最大值為例, 先討論詢問過程中不對陣列做任何修改的情況, 用 idx[k] 記錄 [k-lowbit(k)+1,k] 區間內的最大值, 可以仿照求和時的方法得到:12

3456

7voidinit(intn)

}

}

這種方法在每次呼叫該函式前都必須對陣列進行初始化, 這樣對於資料範圍比較大的時候不是很優美, 這樣我們可以改為:12

3456

78voidinit(intn)

}

}

這樣, 在更新到第k個數時, 所有 t(t然後再來看查詢的問題, 對於區間 [l,r] 把該區間轉化為多個的小區間再進行求最值, 方法是從後往前對每乙個索引數的範圍進行判斷, 如在進行到第k項時,該數控制的範圍是 [k-lowbit(k)+1,k], 如果k-lowbit(k)+1在所求的範圍內的話則將該區間的最值加入最值的判斷,然後轉至地k-lowbit(k),否則的話就只對第k個數進行最值判斷,然後轉至k-1,具體實現如下:12

3456

78910

11intquery(intl,intr)

}

returnans;

}

該查詢的複雜度為log(n)

st演算法的複雜度 o(nlog(n)) / o(1) , 線段樹為 o(nlog(n)) / (log(n)),樹狀陣列 o(空間複雜度 st 為 o(nlog(n)), 線段樹 o(n),常數較大 , 樹狀陣列是 o(n)

程式設計上 st 和 樹狀陣列 都比較容易實現,線段樹**較長

另外線段樹靈活性較大

pku 3264 題:

st    memory: 6372k  time: 1250ms  964b

bit  memory: 716k  time: 1282ms  933b

segtree  未測,要比st更大

然後我們可以進一步擴充套件到邊查詢邊修改的情況

每次直接去更新父親節點自然是不行的, 為了維護索引陣列的正確性,我們在對每個父親節點進行更新時都要查詢他的所有兒子節點,在其中取最優值, 得到**如下:12

3456

789voidmodify(intp,intv,intn)

}

}

複雜度為 o(log^2(n)),  hdu 1754  i hate it  437ms  1776k

另外,該方法還有乙個減枝, 很容易想到,在求最大值時,當某個值更新的值大於原值的時候是沒有必要再去查詢兒子節點的,所以內部迴圈可加乙個判斷來判定是否需要掃瞄兒子節點,可能是資料問題,該題時間並沒有大的變化

樹狀陣列求區間最值

樹狀陣列 binary index tree 利用二進位制的一些性質巧妙的劃分區間,是一種程式設計,時間和空間上都十分理想的求區間和的演算法,同樣我們可以利用樹狀陣列優美的區間劃分方法來求乙個序列的最值 約定以 num 表示原陣列,以 idx 表示索引陣列,lowbit x x x 樹狀陣列求和時通...

樹狀陣列維護區間最值

題目描述 給你乙個1 n的排列和乙個棧,入棧順序給定 你要在不打亂入棧順序的情況下,對陣列進行從大到小排序 當無法完全排序時,請輸出字典序最大的出棧序列 輸入描述 第一行乙個數n 第二行n個數,表示入棧的順序,用空格隔開,結尾無空格 輸出描述 輸出一行n個數表示答案,用空格隔開,結尾無空格 示例1輸...

樹狀陣列之區間最值

數學原理 利用上面的性質,在樹狀陣列的尾部插入資料,來建立乙個樹狀陣列 void push int pos void update int pos,int v int pre c pos pos lowbit pos 父親的位置 更新父親 while pos n 沒有更新父親 else break ...